-
Notifications
You must be signed in to change notification settings - Fork 0
Build fast previews and trusted candidate delivery #67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # Copy outside git or export locally. Never commit real private coordinates. | ||
| HELM_STATUS_CANDIDATE_URL=http://PRIVATE_GUEST_ADDRESS:8123 | ||
| HELM_STATUS_CANDIDATE_HOST=LOCAL_PROXMOX_SSH_ALIAS | ||
| HELM_STATUS_CANDIDATE_ID=LOCAL_GUEST_ID |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,175 @@ | ||
| name: Candidate dress rehearsal | ||
|
|
||
| on: | ||
| workflow_run: | ||
| workflows: [CI] | ||
| types: [completed] | ||
| branches: [main] | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: 1helm-private-dress-rehearsal | ||
| cancel-in-progress: false | ||
|
|
||
| jobs: | ||
| build: | ||
| name: Build exact trusted-main Linux candidate | ||
| if: >- | ||
| github.event.workflow_run.conclusion == 'success' && | ||
| github.event.workflow_run.event == 'push' && | ||
| github.event.workflow_run.head_branch == 'main' && | ||
| github.event.workflow_run.head_repository.full_name == github.repository && | ||
| github.event.repository.full_name == github.repository && | ||
| github.sha == github.event.workflow_run.head_sha && | ||
| github.ref == 'refs/heads/main' | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 60 | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| attestations: write | ||
| outputs: | ||
| artifact-name: ${{ steps.identity.outputs.artifact_name }} | ||
| commit: ${{ steps.identity.outputs.commit }} | ||
| steps: | ||
| - name: Check out the exact successful CI commit | ||
| uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 | ||
| with: | ||
| ref: ${{ github.event.workflow_run.head_sha }} | ||
| fetch-depth: 1 | ||
| persist-credentials: false | ||
|
|
||
| - name: Re-verify trusted repository, ref, event, and SHA | ||
| env: | ||
| CI_HEAD_SHA: ${{ github.event.workflow_run.head_sha }} | ||
| CI_HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} | ||
| CI_HEAD_REPOSITORY: ${{ github.event.workflow_run.head_repository.full_name }} | ||
| CI_EVENT: ${{ github.event.workflow_run.event }} | ||
| CI_CONCLUSION: ${{ github.event.workflow_run.conclusion }} | ||
| CI_WORKFLOW: ${{ github.event.workflow_run.name }} | ||
| run: | | ||
| set -euo pipefail | ||
| test "$GITHUB_REPOSITORY" = "gitcommit90/1Helm" | ||
| test "$CI_HEAD_REPOSITORY" = "$GITHUB_REPOSITORY" | ||
| test "$CI_HEAD_BRANCH" = "main" | ||
| test "$CI_EVENT" = "push" | ||
| test "$CI_CONCLUSION" = "success" | ||
| test "$CI_WORKFLOW" = "CI" | ||
| test "$GITHUB_REF" = "refs/heads/main" | ||
| test "$GITHUB_SHA" = "$CI_HEAD_SHA" | ||
| test "$(git rev-parse HEAD)" = "$CI_HEAD_SHA" | ||
| test -z "$(git status --porcelain)" | ||
|
|
||
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 | ||
| with: | ||
| node-version: "22" | ||
| cache: npm | ||
|
|
||
| - name: Install exact dependencies and builder runtime | ||
| run: | | ||
| set -euo pipefail | ||
| PUPPETEER_SKIP_DOWNLOAD=1 npm ci | ||
| sudo apt-get update | ||
| sudo apt-get install -y podman | ||
|
|
||
| - name: Build sealed OCI image and ready-to-run Linux archive | ||
| env: | ||
| HELM_CANDIDATE_REPOSITORY: gitcommit90/1Helm | ||
| HELM_CANDIDATE_REF: refs/heads/main | ||
| HELM_CANDIDATE_COMMIT: ${{ github.event.workflow_run.head_sha }} | ||
| HELM_CANDIDATE_SOURCE_STATE: trusted-main | ||
| HELM_CANDIDATE_BUILD_ID: candidate-${{ github.event.workflow_run.id }}-${{ github.run_id }}.${{ github.run_attempt }} | ||
| HELM_CANDIDATE_CREATED_AT: ${{ github.event.workflow_run.updated_at }} | ||
| HELM_CANDIDATE_CI_WORKFLOW: CI | ||
| HELM_CANDIDATE_CI_RUN_ID: ${{ github.event.workflow_run.id }} | ||
| HELM_CANDIDATE_CI_CONCLUSION: success | ||
| run: | | ||
| set -euo pipefail | ||
| npm run package:channel-image | ||
| npm run package:linux | ||
|
|
||
| - name: Generate candidate manifest and evidence | ||
| id: identity | ||
| env: | ||
| CI_HEAD_SHA: ${{ github.event.workflow_run.head_sha }} | ||
| run: | | ||
| set -euo pipefail | ||
| version="$(node -p 'require("./package.json").version')" | ||
| archive="dist/1Helm-${version}-linux-node.tgz" | ||
| evidence="dist/candidate-evidence" | ||
| mkdir -p "$evidence" | ||
| HELM_CANDIDATE_ARCHIVE="$archive" \ | ||
| HELM_CANDIDATE_MANIFEST="$evidence/candidate.json" \ | ||
| node scripts/candidate-manifest.mjs | ||
| cp "$archive.sha256" "$evidence/archive.sha256" | ||
| sha256sum "$evidence/candidate.json" > "$evidence/manifest.sha256" | ||
| printf 'artifact_name=1helm-candidate-%s\n' "$CI_HEAD_SHA" >> "$GITHUB_OUTPUT" | ||
| printf 'commit=%s\n' "$CI_HEAD_SHA" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Attest archive provenance on the hosted builder | ||
| id: attest | ||
| uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3 | ||
| with: | ||
| subject-path: dist/1Helm-*-linux-node.tgz | ||
|
|
||
| - name: Retain signed provenance bundle | ||
| env: | ||
| BUNDLE_PATH: ${{ steps.attest.outputs.bundle-path }} | ||
| run: | | ||
| set -euo pipefail | ||
| test -s "$BUNDLE_PATH" | ||
| install -m 0644 "$BUNDLE_PATH" dist/candidate-evidence/provenance.bundle.json | ||
|
|
||
| - name: Upload exact candidate and evidence | ||
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | ||
| with: | ||
| name: ${{ steps.identity.outputs.artifact_name }} | ||
| path: | | ||
| dist/1Helm-*-linux-node.tgz | ||
| dist/candidate-evidence/candidate.json | ||
| dist/candidate-evidence/archive.sha256 | ||
| dist/candidate-evidence/manifest.sha256 | ||
| dist/candidate-evidence/provenance.bundle.json | ||
| if-no-files-found: error | ||
| retention-days: 30 | ||
|
|
||
| deploy: | ||
| name: Install only on private Phase 2 dress rehearsal | ||
| needs: build | ||
| runs-on: [1helm-dress-rehearsal-phase2] | ||
| timeout-minutes: 20 | ||
| permissions: | ||
| contents: read | ||
| actions: read | ||
| steps: | ||
| - name: Download this workflow's exact candidate | ||
| uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 | ||
| with: | ||
| name: ${{ needs.build.outputs.artifact-name }} | ||
| path: candidate-download | ||
|
|
||
| - name: Submit fixed candidate inputs to the root-owned boundary | ||
| env: | ||
| EXPECTED_COMMIT: ${{ needs.build.outputs.commit }} | ||
| run: | | ||
| set -euo pipefail | ||
| test "$GITHUB_REPOSITORY" = "gitcommit90/1Helm" | ||
| test "$EXPECTED_COMMIT" = "${{ github.event.workflow_run.head_sha }}" | ||
| test "${{ github.event.workflow_run.head_branch }}" = "main" | ||
| test "${{ github.event.workflow_run.head_repository.full_name }}" = "$GITHUB_REPOSITORY" | ||
| test "${{ github.event.workflow_run.conclusion }}" = "success" | ||
| archive="$(find candidate-download -maxdepth 1 -type f -name '1Helm-*-linux-node.tgz' -print -quit)" | ||
| test -n "$archive" | ||
| install -m 0600 "$archive" /var/lib/1helm-candidate/inbox/candidate.tgz | ||
| install -m 0600 candidate-download/candidate-evidence/candidate.json /var/lib/1helm-candidate/inbox/candidate.json | ||
| install -m 0600 candidate-download/candidate-evidence/provenance.bundle.json /var/lib/1helm-candidate/inbox/provenance.bundle.json | ||
| sudo -n /usr/local/sbin/1helm-candidate-install | ||
|
|
||
| - name: Publish private installation evidence in the job log | ||
| if: always() | ||
| run: | | ||
| test -r /var/lib/1helm-candidate/evidence/status.json | ||
| python3 /usr/local/lib/1helm-candidate/candidate-boundary.py summary \ | ||
| /var/lib/1helm-candidate/evidence/status.json |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # Delivery contract for coding agents | ||
|
|
||
| The default delivery mode in this repository is **PREVIEW ONLY**. Implement and | ||
| verify a small, explicitly requested change, then report it for review. | ||
|
|
||
| Unless the owner explicitly requests a stable promotion, do not: | ||
|
|
||
| - bump versions or edit release notes for a release; | ||
| - create or publish tags, releases, or artifacts; | ||
| - deploy the public website or update stable or its release metadata; | ||
| - change production data, infrastructure, containers, VMs, or services; or | ||
| - broaden the requested scope. | ||
|
|
||
| Keep changes focused. Run the narrowest relevant tests while iterating, then run | ||
| the full CI contract (`npm run ci`) before merge. Never weaken a check to make a | ||
| change pass. | ||
|
|
||
| Every handoff must briefly name changed files, checks run and their results, | ||
| known risks, rollback steps, and whether stable or any external system was | ||
| touched. | ||
|
|
||
| Maintainer policy and release mechanics remain authoritative in | ||
| [`docs/GOVERNANCE.md`](docs/GOVERNANCE.md) and | ||
| [`docs/release-lifecycle.md`](docs/release-lifecycle.md). This file adds the | ||
| agent default; it does not replace those documents. |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # Claude Code instructions | ||
|
|
||
| Follow [AGENTS.md](AGENTS.md) as the authoritative delivery contract for all | ||
| work in this repository. |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| # Delivery canary plan | ||
|
|
||
| ## Phase 0 boundary | ||
|
|
||
| Phase 0 creates documentation and read-only visibility only. It does not | ||
| create or modify infrastructure, containers, VMs, services, deployment targets, | ||
| releases, stable metadata, or production data. | ||
|
|
||
| LXC 112 on `pve2` remains unchanged as the legacy **v0.0.38 updater fixture**. | ||
| It is evidence for the prior-version update path, not a general-purpose canary. | ||
| No experiment, candidate install, reset, or cleanup may repurpose it. | ||
|
|
||
| ## Phase 2 private dress rehearsal | ||
|
|
||
| Phase 2 was separately approved. It creates one fresh, unprivileged LXC with its | ||
| own identity, storage, private network address, and lifecycle. It does not share | ||
| production data, credentials, release metadata, or the legacy fixture. The | ||
| guest ID, address, and hypervisor access stay in local operator configuration, | ||
| not this public repository. | ||
|
|
||
| After `CI` succeeds for a push to trusted `main`, `Candidate dress rehearsal` | ||
| checks out that exact CI SHA on a GitHub-hosted builder. It builds the sealed OCI | ||
| image and ready-to-run Linux archive without a version bump or GitHub Release, | ||
| embeds source/build identity, emits a digest manifest, signs GitHub artifact | ||
| provenance, and retains all evidence as a workflow artifact. Only then does its | ||
| deployment job select the uniquely labelled repository runner in the dedicated | ||
| guest. | ||
|
|
||
| The runner cannot install arbitrary bytes. A fixed root-owned command copies | ||
| the fixed inbox files, requires signed provenance from the trusted candidate | ||
| workflow on `main`, rejects self-hosted provenance, and requires the outer | ||
| manifest, embedded identity, archive digest, source SHA, version, and sealed OCI | ||
| digest to agree. It then reuses the immutable release store, service health | ||
| check, and automatic rollback in the Linux installer. The status record contains: | ||
|
|
||
| - canary role, hypervisor/guest identity, and health endpoint; | ||
| - current version and candidate version; | ||
| - exact source commit plus artifact name and SHA-256 digest; | ||
| - service and application health, check time, result, and any uncertainty; | ||
| - CI workflow/run result and candidate build identity; | ||
| - install health and time; and | ||
| - previous candidate plus rollback result/time. | ||
|
|
||
| Unknown metadata must be reported as unknown, never inferred from a nearby | ||
| checkout, tag, or responding port. | ||
|
|
||
| ## Rollback gate | ||
|
|
||
| The dedicated guest starts from a documented clean baseline. Each accepted | ||
| candidate becomes an immutable, digest-named release directory. Before changing | ||
| the current symlink or host contract, the existing Linux transaction snapshots | ||
| the prior current release, runtime files, units, and unit state. A failed or | ||
| uncertain service/API health check restores that exact prior contract and proves | ||
| the restored service healthy. The candidate evidence records both failure and | ||
| rollback outcome. This is application rollback inside the dedicated guest; no | ||
| Proxmox snapshot, Stable change, or LXC 112 action is part of the automation. | ||
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ποΈ Data Integrity & Integration | π‘ Minor | β‘ Quick win
Align the status field list with the implemented schema.
status.jsondoes not contain the canary role, hypervisor identity, guest identity, health endpoint, or artifact name.Remove these fields from this list, or state that Phase 0 combines them from local configuration. Keep the candidate evidence fields separate from locally configured environment metadata.
π€ Prompt for AI Agents