From 9a49b3b108b9faaec45f1ee313489ccc1ec3ea2c Mon Sep 17 00:00:00 2001 From: Vitor Carvalho Date: Wed, 14 Oct 2026 15:58:24 +0100 Subject: [PATCH 1/2] OneDev CI (step 1): checks and images jobs, no push yet - .onedev-buildspec.yml (validated with tod build check-spec): checks = just lint + just validate; images = check-tags on PRs, then build, trivy scan and smoke test of new tags. Executor remote, docker:29.8.2-cli with the Docker socket. - scripts/ci-images.sh: build/scan/smoke/(push) outside GitHub Actions. - scripts/check-tags.sh: the check-tags logic, used by just and CI. - just lint-gh: actionlint + zizmor, only for the GitHub workflows (zizmor is glibc-only; the OneDev job runs on Alpine). Co-Authored-By: Claude Opus 5.5 --- .github/workflows/checks.yml | 1 + .onedev-buildspec.yml | 87 ++++++++++++++++++++++++++++++++++++ justfile | 47 +++---------------- scripts/check-tags.sh | 44 ++++++++++++++++++ scripts/ci-images.sh | 45 +++++++++++++++++++ 5 files changed, 184 insertions(+), 40 deletions(-) create mode 100644 .onedev-buildspec.yml create mode 100755 scripts/check-tags.sh create mode 100755 scripts/ci-images.sh diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index cb89f54..2da453b 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -27,6 +27,7 @@ jobs: persist-credentials: false - uses: jdx/mise-action@9149ea85001c7435d5a66bb127d6a1b6227cb0a5 # v5.0.0 - run: just lint + - run: just lint-gh env: GH_TOKEN: ${{ github.token }} # zizmor online audits - run: just validate diff --git a/.onedev-buildspec.yml b/.onedev-buildspec.yml new file mode 100644 index 0000000..765adbf --- /dev/null +++ b/.onedev-buildspec.yml @@ -0,0 +1,87 @@ +version: 52 +jobs: +- name: checks + jobExecutor: remote + steps: + - type: CheckoutStep + name: checkout + cloneCredential: + type: DefaultCredential + withLfs: false + withSubmodules: false + condition: SUCCESSFUL + optional: false + - type: CommandStep + name: lint and validate + runInContainer: true + image: docker:29.8.2-cli + interpreter: + type: PosixInterpreter + shell: sh + commands: | + set -eu + apk add --no-cache -q bash git jq python3 curl mise + git config --global --add safe.directory '*' + mise trust -q .mise.toml + mise install -q + mise exec -- just lint + mise exec -- just validate + runAs: 0:0 + useTTY: true + condition: SUCCESSFUL + optional: false + triggers: + - type: PullRequestUpdateTrigger + branches: main + - type: BranchUpdateTrigger + branches: main + userMatch: anyone + retryCondition: never + maxRetries: 3 + retryDelay: 30 + timeout: 3600 +- name: images + jobExecutor: remote + steps: + - type: CheckoutStep + name: checkout + cloneCredential: + type: DefaultCredential + withLfs: false + withSubmodules: false + condition: SUCCESSFUL + optional: false + - type: CommandStep + name: check tags, build, scan, smoke test + runInContainer: true + image: docker:29.8.2-cli + interpreter: + type: PosixInterpreter + shell: sh + commands: | + set -eu + apk add --no-cache -q bash git jq python3 curl + git config --global --add safe.directory '*' + # On a pull request the build runs on a merge commit: its first + # parent is the target branch, which check-tags compares against. + if [ "$(git rev-list --parents -n 1 HEAD | wc -w)" -gt 2 ]; then + bash scripts/check-tags.sh "$(git rev-parse HEAD^1)" + fi + bash scripts/ci-images.sh + runAs: 0:0 + envVars: + - name: COMMIT + value: '@commit_hash@' + useTTY: true + condition: SUCCESSFUL + optional: false + triggers: + - type: PullRequestUpdateTrigger + branches: main + - type: BranchUpdateTrigger + branches: main + userMatch: anyone + retryCondition: never + maxRetries: 3 + retryDelay: 30 + timeout: 7200 diff --git a/justfile b/justfile index 74234cd..089066d 100644 --- a/justfile +++ b/justfile @@ -17,17 +17,20 @@ templates := "node-js php-wordpress ops" default: @just --list -# Check formatting, Dockerfiles, JSON, scripts, workflows, Renovate config and secrets +# Check formatting, Dockerfiles, JSON, scripts, Renovate config and secrets lint: terraform fmt -check -recursive hadolint --config .hadolint.yaml */build/Dockerfile for f in */build/*.json; do python3 -m json.tool "$f" >/dev/null || exit 1; done shellcheck tests/*.sh scripts/*.sh - actionlint check-jsonschema --builtin-schema vendor.renovate renovate.json - zizmor -q --no-progress --min-severity low .github/workflows gitleaks dir . --no-banner --redact +# Check the GitHub workflows (GitHub only; removed after the OneDev move) +lint-gh: + actionlint + zizmor -q --no-progress --min-severity low .github/workflows + # terraform validate each template (in a temp copy: no lock file left behind) validate: #!/usr/bin/env bash @@ -45,43 +48,7 @@ validate: # A change under build/ needs a new image tag. A tag already in GHCR is # accepted only if it was built from the same build/. check-tags base="origin/main": - #!/usr/bin/env bash - set -euo pipefail - err() { if [ -n "${GITHUB_ACTIONS:-}" ]; then echo "::error file=$1::$2"; else echo "error: $2" >&2; fi; } - fail=0 - for t in {{templates}}; do - new="$(just image "$t")" - old="$(git show "{{base}}:$t/main.tf" 2>/dev/null | scripts/image-ref.sh - 2>/dev/null || true)" - if [ "$new" = "$old" ]; then - if git diff --quiet "{{base}}...HEAD" -- "$t/build"; then - echo "ok: $t (unchanged: $new)" - else - err "$t/main.tf" "$t/build changed, but the image tag did not: $new"; fail=1 - fi - else - # Fail closed: only an explicit "absent" counts as a new tag. - state="$(scripts/image-state.sh "$new")" || { err "$t/main.tf" "cannot check $new in GHCR"; fail=1; continue; } - if [ "$state" = present ]; then - # An existing tag is fine only if it was built from the same build/ - # (security rebuild by scan.yml, or a rollback). Never re-pushed. - rev="$(scripts/image-revision.sh "$new")" || { err "$t/main.tf" "cannot read the revision of $new"; fail=1; continue; } - if git cat-file -e "$rev^{commit}" 2>/dev/null && git diff --quiet "$rev" HEAD -- "$t/build"; then - # The build workflow skips existing tags: scan it here, it may - # have CVEs found after it was built. - if docker pull -q "$new" >/dev/null && scripts/trivy-scan.sh "$new"; then - echo "ok: $t (existing tag, same build/ as ${rev:0:7}, trivy clean: $new)" - else - err "$t/main.tf" "existing tag has fixable CRITICAL vulnerabilities (or the scan failed): $new"; fail=1 - fi - else - err "$t/main.tf" "tag already in GHCR, built from a different build/ (${rev:0:7}): $new"; fail=1 - fi - else - echo "ok: $t (new tag: $new)" - fi - fi - done - exit "$fail" + scripts/check-tags.sh "{{base}}" # Image used by a template (from main.tf) image t: diff --git a/scripts/check-tags.sh b/scripts/check-tags.sh new file mode 100755 index 0000000..2719116 --- /dev/null +++ b/scripts/check-tags.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# A change under