chore: propagate main into development - #25
Merged
Merged
Conversation
Extends CI, CodeQL, and the Docker build to actually validate the new branch structure — previously all three only triggered on main, so pushes to development/nightly/feature/** got zero coverage. Docker builds on those branches now tag with the (sanitized) branch name via docker/metadata-action's built-in type=ref,event=branch, rather than producing no tag at all. Three new workflows implement the promotion flow, mirroring Charon's pattern but trimmed to what Hestia actually needs (no Orthrus-style per-service builds, cosign signing, or Go-specific health-check machinery): - sync-nightly.yml: daily direct fast-forward (or reset) of nightly to development's HEAD, force-pushed — not a PR, since nightly is meant to track development continuously without review. - promote-nightly-to-main.yml: weekly PR nightly -> main, gated on CI having actually passed for nightly's current HEAD. Merge-commit-only instructions in the PR body, since squash-merging would collapse feat:/fix: commits into one bullet list that release-please can't parse. - propagate-main-to-development.yml: on push to main, opens a draft PR carrying those commits down to development — for hotfixes/CI commits landing directly on main. Deliberately skips nightly (it picks changes up via the daily sync instead). No-ops correctly after a routine nightly->main promotion merge, since main's content already matches development at that point (nothing to propagate). sync-nightly.yml and promote-nightly-to-main.yml's PR creation both fall back to GITHUB_TOKEN if CI_TRIGGER_TOKEN isn't set, but a push/PR made with the default token doesn't trigger other workflows — so without that secret, CI won't actually run on nightly until something else touches it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
pr-title-lint.yml checks every PR title regardless of source, and neither "Propagate main into development" nor "Promote nightly to main (...)" had a conventional-commit prefix — both failed the check immediately on creation. Also retitled the already-open PR #25 directly via the API since this fix only affects future runs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
🤖 I have created a release *beep* *boop* --- ## [0.2.1](hestia-v0.2.0...hestia-v0.2.1) (2026-08-09) ### Bug Fixes * prefix auto-created PR titles with chore: for pr-title-lint ([4b3c8b9](4b3c8b9)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
Ran a full local security audit rather than just trusting the GH Code
Scanning count (which was stale — it won't refresh until a new build
pushes, and our last one predates today's Debian package patches
upstream).
Measured three base image candidates with a full-severity Trivy scan
before deciding:
node:24.19.0-slim (Debian, previous) 152 findings, 0 HIGH/CRITICAL*
gcr.io/distroless/nodejs24-debian12 38 findings, 6 HIGH/CRITICAL
node:24.19.0-alpine 11 findings, 0 HIGH/CRITICAL
* 0 HIGH/CRITICAL only because the base image tag had been silently
republished with Debian patches since our last build — all 13 CVE IDs
previously catalogued in these files were completely gone. Distroless
was worse than expected since it's still Debian-package-based
underneath; Alpine's musl/apk package set won outright.
Switched to node:24.19.0-alpine. Also stripped the bundled npm CLI from
the runtime stage (never invoked there — CMD is `node server.js`), which
eliminated the last 11 fixable findings: npm's own tar/undici/ip-address,
not Hestia's dependencies (confirmed absent from /app/node_modules both
before and after by inspecting the built image directly).
Net result, verified by rebuilding and rescanning the actual image with
both Trivy and Grype (not assumed): 152 -> 0 (Trivy), 3 -> 1 unique CVE
(Grype). The one remaining finding (CVE-2025-60876, BusyBox wget
request-splitting, no fix yet) is documented in SECURITY.md/.trivyignore/
.grype.yaml — Hestia never invokes wget or any busybox applet.
All 13 stale Debian-specific suppression entries removed from
.trivyignore/.grype.yaml/SECURITY.md rather than left dangling against
CVEs that no longer apply to this image.
No new Renovate regex managers needed: the base image is pinned to a
specific version tag (node:24.19.0-alpine), which Renovate's native
dockerfile manager already tracks the same way it tracked the slim tag —
no manually-pinned package versions were introduced.
Verified: full build (multi-stage, better-sqlite3 compiles against musl),
container boots and serves correctly, and the complete e2e suite
(signup/chores/points/PIN gates/rewards/redemption/calendar/reminders)
passes running against this exact image — not just checked that it boots.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
🤖 I have created a release *beep* *boop* --- ## [0.2.2](hestia-v0.2.1...hestia-v0.2.2) (2026-08-09) ### Bug Fixes * point Renovate base branch to development instead of main ([dda7656](dda7656)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
A PR-triggered build for PR #25 ran for 2+ hours today while the equivalent push-triggered build for the identical commit finished normally in ~7 minutes. Root cause: docker-build.yml was running two concurrent multi-arch (QEMU-emulated arm64) builds of the exact same content at once — the push-to-main trigger and the pull_request trigger both fired for the same SHA, since PR #25 (opened by propagate-main-to-development.yml) has main as its head. Four changes: - Skip the job entirely for PRs opened by github-actions[bot] (our own propagate/promotion automation). Their head is always a branch that already got a push-triggered build for that exact commit — a second build of identical content is pure waste, and running two QEMU arm64 builds concurrently is the most likely reason one hung instead of failing cleanly. - PR builds now target linux/amd64 only, skipping QEMU-emulated arm64 entirely. PR images are for validation, not the published artifact; real multi-arch images still come from push-to-main/development/nightly and releases. Removes the likeliest hang source from the highest-frequency trigger. - Wrapped the actual build in nick-fields/retry (2 attempts, 15 min each, 15s wait between). docker/build-push-action has no retry support of its own, so this meant switching to a raw `docker buildx build` invocation inside the retry command, reconstructing --tag/--label args from metadata-action's output and capturing the digest via --iidfile. Verified locally (mock metadata parsing, then a real build+iidfile capture) before trusting it in CI. - Added a job-level 40-minute timeout as a hard ceiling regardless of cause, plus a disk-space-cleanup step before the build as cheap insurance against resource exhaustion during multi-arch builds. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The 2026-08-09 CI hang wasn't fixed by the retry/timeout wrapper alone — confirmed via two full retry attempts on the push-triggered build, both crashing at the identical point: `qemu: uncaught target signal 4 (Illegal instruction) - core dumped` partway through `npm ci`'s arm64 deps stage (esbuild's postinstall step executing its downloaded arm64 binary under QEMU user-mode emulation). Deterministic, not transient — retries just burned 2x15 minutes before failing every time. Replaces the single cross-platform QEMU build with a matrix of native per-architecture builds (ubuntu-latest for amd64, ubuntu-24.04-arm for arm64 — free hosted runners on public repos), each pushing its image by digest, merged into one multi-arch manifest per tag by a follow-up job. QEMU/setup-qemu-action is no longer used anywhere in this workflow. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The merge job's manifest-list creation and registry pushes both worked, but Trivy failed scanning the picked digest: "no child with platform linux/amd64 in index ...". buildx attaches build provenance attestations by default, which wraps even a single-platform push in a 2-entry OCI index (image manifest + attestation manifest) — so the exported digest pointed at an index, not the plain manifest Trivy expected to resolve directly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CodeQL's concurrency group was keyed on branch name for both push and PR events, so pushing a second commit to main before CodeQL finished for the first cancelled that first commit's scan outright — leaving it with a permanently cancelled check instead of a result. No branch protection rule requires CodeQL to pass, so nothing was actually blocked, but every commit's scan should still run to completion for the security audit trail. PR events keep cancelling superseded commits on the same PR, which is correct there. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Wikid82
marked this pull request as ready for review
August 10, 2026 00:55
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automated PR carrying commits pushed directly to
main(hotfixes, CI-generatedcommits) down into
development. nightly is intentionally skipped — it picksthese up via the daily development sync instead.
Triggered by push 10b086d to main.