Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dependabot-auto-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
persist-credentials: false

- name: Setup Node.js 24.x
uses: actions/setup-node@v4
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: '24'

Expand Down
109 changes: 109 additions & 0 deletions .github/workflows/docker-publish-reusable.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Reusable: build a Docker image, push it to GHCR, and trigger an instant
# Komodo deploy. Used by the bot repos (asia-trip-bot, kurwa_bot).
#
# Each caller keeps its own `on: push` trigger with a repo-specific `paths:`
# filter (the set of source paths that should rebuild the image), then
# delegates here:
#
# jobs:
# publish:
# uses: roleme/workflows/.github/workflows/docker-publish-reusable.yml@main
# permissions:
# contents: read
# packages: write
# with:
# image: ghcr.io/<owner>/<repo>
# komodo-stack: <stack-name>
# komodo-host: <komodo-host>
# secrets: inherit
#
# Deploy trigger: after the GHCR push, the final step curls Komodo's per-stack
# GitHub listener, HMAC-signing the body with KOMODO_WEBHOOK_SECRET (the
# stack's webhook_secret). Stacks have webhook_force_deploy=true so Komodo runs
# a real DeployStack (pull) — a new :latest leaves compose.yaml unchanged, so
# DeployStackIfChanged would no-op. Without this step the stack still updates
# via Komodo's poll; the webhook just makes it near-instant.
name: docker-publish (reusable)

on:
workflow_call:
inputs:
image:
description: Fully-qualified GHCR image name (e.g. ghcr.io/owner/repo)
required: true
type: string
komodo-stack:
description: Komodo stack name for the deploy listener URL
required: true
type: string
komodo-host:
description: Komodo host for the deploy listener (e.g. komodo.example.com)
required: true
type: string
context:
description: Docker build context
required: false
type: string
default: .
secrets:
KOMODO_WEBHOOK_SECRET:
description: HMAC secret for the Komodo stack webhook
required: true

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: false

- name: Log in to GitHub Container Registry
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract image metadata (tags + labels)
id: meta
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6
with:
images: ${{ inputs.image }}
tags: |
type=raw,value=latest

- name: Set up Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4

- name: Build and push
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7
with:
context: ${{ inputs.context }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Trigger Komodo deploy
# All interpolated values come from workflow inputs/secrets (trusted
# caller config, not event payload). They are passed via env and quoted
# so they are never spliced into the command line.
env:
KOMODO_WEBHOOK_SECRET: ${{ secrets.KOMODO_WEBHOOK_SECRET }}
KOMODO_HOST: ${{ inputs.komodo-host }}
KOMODO_STACK: ${{ inputs.komodo-stack }}
run: |
BODY='{"ref":"refs/heads/main"}'
SIG="sha256=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$KOMODO_WEBHOOK_SECRET" | awk '{print $2}')"
curl -fsSL -X POST \
"https://${KOMODO_HOST}/listener/github/stack/${KOMODO_STACK}/deploy" \
-H "Content-Type: application/json" \
-H "X-Hub-Signature-256: $SIG" \
--data "$BODY"
44 changes: 44 additions & 0 deletions .github/workflows/validate-renovate-reusable.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Reusable Renovate config validation.
#
# Validates renovate.json against the Renovate schema so a broken config is
# caught in a PR instead of silently failing at Renovate runtime. Callers add
# a thin wrapper triggered by pull_request touching renovate.json:
#
# jobs:
# validate-renovate:
# uses: roleme/workflows/.github/workflows/validate-renovate-reusable.yml@main
#
# Node is required for renovate-config-validator (shipped in the renovate npm
# package).
name: validate-renovate (reusable)

on:
workflow_call:
inputs:
config-file:
description: Path to the Renovate config file to validate
required: false
type: string
default: renovate.json

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: false

- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: 24

- name: Validate Renovate config
# The config path comes from a workflow input (trusted caller), but pass
# it via env and quote it so it is never spliced into the command line.
env:
CONFIG_FILE: ${{ inputs.config-file }}
run: npx --yes --package renovate@43 renovate-config-validator "$CONFIG_FILE"
31 changes: 31 additions & 0 deletions .github/workflows/zizmor-reusable.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Reusable zizmor (GitHub Actions security) scan.
#
# Callers add a thin wrapper that triggers on pull_request touching
# .github/workflows/** and delegates here:
#
# jobs:
# zizmor:
# uses: roleme/workflows/.github/workflows/zizmor-reusable.yml@main
#
# advanced-security: false surfaces results as workflow annotations (not a
# SARIF upload), so no security-events permission is needed — contents: read
# is enough.
name: zizmor (reusable)

on:
workflow_call: {}

permissions:
contents: read

jobs:
zizmor:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: false
- name: Run zizmor
uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6
with:
advanced-security: false
10 changes: 9 additions & 1 deletion renovate-presets/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,13 @@
"extends": ["config:recommended", "helpers:pinGitHubActionDigests"],
"minimumReleaseAge": "10 days",
"transitiveRemediation": true,
"labels": ["dependencies", "renovate"]
"labels": ["dependencies", "renovate"],
"packageRules": [
{
"description": "GitHub Actions patch/minor — automerge. Renovate is the primary updater for actions (Dependabot is only a backup); the 10-day minimumReleaseAge above still applies before the merge.",
"matchManagers": ["github-actions"],
"matchUpdateTypes": ["patch", "minor"],
"automerge": true
}
]
}