Skip to content

Commit cecfea5

Browse files
committed
fix(ci): restore real gates and cache manifest artifacts
1 parent f844f04 commit cecfea5

53 files changed

Lines changed: 2935 additions & 1906 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: Fetch manifest-selected release inputs
2+
description: Restore, fetch, verify, and retain immutable manifest-addressed blobs.
3+
4+
inputs:
5+
manifest-url:
6+
description: Fresh mutable manifest URL that selects the artifact set.
7+
required: true
8+
kind:
9+
description: Manifest artifact family.
10+
required: true
11+
architecture:
12+
description: Optional profile architecture selection.
13+
required: false
14+
default: ""
15+
output:
16+
description: Verified release-input output directory.
17+
required: true
18+
bootstrap-manifest-url:
19+
description: Optional manifest used only for an absent first-party channel.
20+
required: false
21+
default: ""
22+
allow-empty-profiles:
23+
description: Permit an explicitly empty bootstrap profile set.
24+
required: false
25+
default: "false"
26+
27+
runs:
28+
using: composite
29+
steps:
30+
- name: Restore manifest-addressed blob cache
31+
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684
32+
with:
33+
path: target/release-input-cache
34+
key: capsem-release-blobs-v1-${{ runner.os }}-${{ inputs.architecture || inputs.kind }}-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}
35+
restore-keys: |
36+
capsem-release-blobs-v1-${{ runner.os }}-${{ inputs.architecture || inputs.kind }}-
37+
38+
- name: Fetch and verify manifest-selected inputs
39+
id: fetch
40+
shell: bash
41+
run: |
42+
set -euo pipefail
43+
args=(
44+
--manifest-url "${{ inputs.manifest-url }}"
45+
--kind "${{ inputs.kind }}"
46+
--output "${{ inputs.output }}"
47+
--cache-dir target/release-input-cache
48+
)
49+
if [[ -n "${{ inputs.architecture }}" ]]; then
50+
args+=(--architecture "${{ inputs.architecture }}")
51+
fi
52+
if [[ -n "${{ inputs.bootstrap-manifest-url }}" ]]; then
53+
args+=(--bootstrap-manifest-url "${{ inputs.bootstrap-manifest-url }}")
54+
fi
55+
if [[ "${{ inputs.allow-empty-profiles }}" == "true" ]]; then
56+
args+=(--allow-empty-profiles)
57+
fi
58+
uv run python scripts/fetch-release-artifacts.py "${args[@]}"
59+
uv run python scripts/verify-release-inputs.py \
60+
--input-dir "${{ inputs.output }}"
61+
cache_misses="$(uv run python -c \
62+
'import json,sys; print(json.load(open(sys.argv[1]))["cache"]["misses"])' \
63+
"${{ inputs.output }}/release-inputs.json")"
64+
echo "cache-misses=$cache_misses" >> "$GITHUB_OUTPUT"
65+
66+
- name: Save updated manifest-addressed blob cache
67+
if: steps.fetch.outputs.cache-misses != '0'
68+
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684
69+
with:
70+
path: target/release-input-cache
71+
key: capsem-release-blobs-v1-${{ runner.os }}-${{ inputs.architecture || inputs.kind }}-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}

.github/workflows/ci.yaml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ jobs:
144144
run: cd release-site && pnpm install --frozen-lockfile
145145

146146
- name: Frontend dependency audit
147-
continue-on-error: true
148147
run: python3 scripts/audit-pnpm-bulk.py --project-dir frontend
149148

150149
- name: Install prebuilt Rust tools
@@ -352,11 +351,19 @@ jobs:
352351
test -r /dev/kvm -a -w /dev/kvm
353352
test -r /dev/vhost-vsock -a -w /dev/vhost-vsock
354353
354+
- name: Pull existing stable profile assets
355+
uses: ./.github/actions/fetch-release-inputs
356+
with:
357+
manifest-url: https://release.capsem.org/assets/stable/manifest.json
358+
kind: profiles
359+
architecture: x86_64
360+
output: target/ci-install-profile-inputs
361+
355362
- name: Build host builder Docker image
356363
run: just _build-host-image
357364

358365
- name: Run install e2e tests
359-
run: just _gate-install
366+
run: CAPSEM_INSTALL_PROFILE_INPUTS=target/ci-install-profile-inputs just _gate-install
360367

361368
- name: Upload install and glow-up evidence on failure
362369
if: failure()

.github/workflows/fast-gate.yaml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Reusable fast and static gate
2+
3+
on:
4+
workflow_call:
5+
6+
permissions:
7+
contents: read
8+
9+
jobs:
10+
static:
11+
runs-on: ubuntu-24.04
12+
timeout-minutes: 120
13+
steps:
14+
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd
15+
16+
- uses: extractions/setup-just@f8a3cce218d9f83db3a2ecd90e41ac3de6cdfd9b
17+
18+
- uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86
19+
20+
- uses: dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c
21+
with:
22+
toolchain: 1.97.1
23+
components: llvm-tools
24+
targets: aarch64-unknown-linux-musl,x86_64-unknown-linux-musl
25+
26+
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32
27+
with:
28+
key: reusable-static-gate
29+
30+
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320
31+
with:
32+
version: 10
33+
34+
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444
35+
with:
36+
node-version: 24
37+
cache: pnpm
38+
cache-dependency-path: |
39+
frontend/pnpm-lock.yaml
40+
docs/pnpm-lock.yaml
41+
site/pnpm-lock.yaml
42+
release-site/pnpm-lock.yaml
43+
44+
- name: Install prebuilt Rust gate tools
45+
uses: taiki-e/install-action@07b4745e0c39a41822af610387492e3e53aa222b
46+
with:
47+
tool: cargo-audit@0.22.1,cargo-llvm-cov@0.8.5,b3sum@1.8.5,cargo-sbom,tauri-cli
48+
49+
- name: Run shared static module
50+
run: just _test-static

.github/workflows/release-assets.yaml

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ jobs:
3838
with:
3939
channel: ${{ inputs.channel }}
4040

41+
fast-gate:
42+
uses: ./.github/workflows/fast-gate.yaml
43+
4144
resolve-current-binary:
4245
needs: runtime-preflight
4346
runs-on: ubuntu-latest
@@ -70,21 +73,26 @@ jobs:
7073
--bootstrap-missing-first-party \
7174
--output target/channel-source/manifest.json
7275
73-
- name: Fetch exact deployed public-before cohorts
76+
- name: Fetch exact deployed public-before package
77+
uses: ./.github/actions/fetch-release-inputs
78+
with:
79+
manifest-url: ${{ env.ASSET_MANIFEST_URL }}
80+
bootstrap-manifest-url: file://${{ github.workspace }}/target/channel-source/manifest.json
81+
kind: packages
82+
output: target/profile-public-before/packages
83+
84+
- name: Fetch exact deployed public-before profiles
85+
uses: ./.github/actions/fetch-release-inputs
86+
with:
87+
manifest-url: ${{ env.ASSET_MANIFEST_URL }}
88+
bootstrap-manifest-url: file://${{ github.workspace }}/target/channel-source/manifest.json
89+
allow-empty-profiles: "true"
90+
kind: profiles
91+
architecture: x86_64
92+
output: target/profile-public-before/profiles
93+
94+
- name: Prove public-before cohorts use one manifest
7495
run: |
75-
uv run python scripts/fetch-release-artifacts.py \
76-
--manifest-url "$ASSET_MANIFEST_URL" \
77-
--bootstrap-manifest-url "file://$PWD/target/channel-source/manifest.json" \
78-
--kind packages \
79-
--output target/profile-public-before/packages
80-
uv run python scripts/fetch-release-artifacts.py \
81-
--manifest-url "$ASSET_MANIFEST_URL" \
82-
--bootstrap-manifest-url "file://$PWD/target/channel-source/manifest.json" \
83-
--allow-empty-profiles \
84-
--kind profiles \
85-
--output target/profile-public-before/profiles
86-
uv run python scripts/verify-release-inputs.py \
87-
--input-dir target/profile-public-before/packages
8896
uv run python scripts/verify-release-inputs.py \
8997
--input-dir target/profile-public-before/profiles
9098
cmp \
@@ -130,7 +138,7 @@ jobs:
130138
--project "$RELEASE_CHANNEL_PROJECT"
131139
132140
build-assets:
133-
needs: [cloudflare-release-site-preflight, resolve-current-binary]
141+
needs: [cloudflare-release-site-preflight, resolve-current-binary, fast-gate]
134142
strategy:
135143
matrix:
136144
include:
@@ -239,9 +247,6 @@ jobs:
239247
test -r /dev/kvm -a -w /dev/kvm
240248
test -r /dev/vhost-vsock -a -w /dev/vhost-vsock
241249
242-
- name: Run shared static module
243-
run: just _test-static
244-
245250
- name: Prepare exact profile and pulled binary pairing
246251
run: |
247252
set -euo pipefail

.github/workflows/release.yaml

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ jobs:
3737
with:
3838
channel: ${{ inputs.channel }}
3939

40+
fast-gate:
41+
uses: ./.github/workflows/fast-gate.yaml
42+
4043
resolve-channel-source:
4144
needs: runtime-preflight
4245
runs-on: ubuntu-latest
@@ -54,19 +57,23 @@ jobs:
5457
--channel "$RELEASE_CHANNEL" \
5558
--output target/channel-source/manifest.json
5659
57-
- name: Fetch exact deployed public-before cohorts
60+
- name: Fetch exact deployed public-before packages
61+
uses: ./.github/actions/fetch-release-inputs
62+
with:
63+
manifest-url: ${{ env.ASSET_MANIFEST_URL }}
64+
kind: packages
65+
output: target/binary-public-before/packages
66+
67+
- name: Fetch exact deployed public-before profiles
68+
uses: ./.github/actions/fetch-release-inputs
69+
with:
70+
manifest-url: ${{ env.ASSET_MANIFEST_URL }}
71+
kind: profiles
72+
architecture: x86_64
73+
output: target/binary-public-before/profiles
74+
75+
- name: Prove public-before cohorts use one manifest
5876
run: |
59-
set -euo pipefail
60-
uv run python scripts/fetch-release-artifacts.py \
61-
--manifest-url "$ASSET_MANIFEST_URL" \
62-
--kind packages \
63-
--output target/binary-public-before/packages
64-
uv run python scripts/fetch-release-artifacts.py \
65-
--manifest-url "$ASSET_MANIFEST_URL" \
66-
--kind profiles \
67-
--output target/binary-public-before/profiles
68-
uv run python scripts/verify-release-inputs.py \
69-
--input-dir target/binary-public-before/packages
7077
uv run python scripts/verify-release-inputs.py \
7178
--input-dir target/binary-public-before/profiles
7279
cmp \
@@ -87,7 +94,7 @@ jobs:
8794
path: target/binary-public-before/profiles/
8895

8996
preflight:
90-
needs: runtime-preflight
97+
needs: [runtime-preflight, fast-gate]
9198
runs-on: macos-14
9299
steps:
93100
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd
@@ -849,10 +856,7 @@ jobs:
849856
name: binary-channel-candidate
850857
path: target/binary-channel/
851858

852-
- name: Run shared static module
853-
run: just _test-static
854-
855-
- name: Resolve exact candidate-after profiles
859+
- name: Verify exact public-before cohorts
856860
run: |
857861
uv run python scripts/verify-release-inputs.py \
858862
--input-dir target/binary-public-before/packages
@@ -861,10 +865,17 @@ jobs:
861865
cmp \
862866
target/binary-public-before/packages/manifest.json \
863867
target/binary-public-before/profiles/manifest.json
864-
uv run python scripts/fetch-release-artifacts.py \
865-
--manifest-url "file://$PWD/target/binary-channel/$RELEASE_CHANNEL/manifest.json" \
866-
--kind profiles \
867-
--output target/candidate-profile-inputs
868+
869+
- name: Resolve exact candidate-after profiles
870+
uses: ./.github/actions/fetch-release-inputs
871+
with:
872+
manifest-url: file://${{ github.workspace }}/target/binary-channel/${{ inputs.channel }}/manifest.json
873+
kind: profiles
874+
architecture: x86_64
875+
output: target/candidate-profile-inputs
876+
877+
- name: Stage exact candidate-after profiles
878+
run: |
868879
uv run python scripts/verify-release-inputs.py \
869880
--input-dir target/candidate-profile-inputs
870881
uv run python scripts/stage-release-test-inputs.py \

AGENTS.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,12 @@ just release-profile <channel> <profile>
3737
- A profile requiring new code is published immutably but remains inactive.
3838
The following binary release consumes that staged profile without rebuilding
3939
it and activates only the fully tested compatible graph.
40-
- The manifest is the authority. Existing SBOM, OBOM, attestations, and GitHub
41-
logs are the evidence; do not add a parallel release ledger or result file.
40+
- The manifest is the bible: if an artifact is not selected by it, it does not
41+
exist for release, update, cache, test, or boot. Fetch mutable manifests
42+
fresh. Cache immutable bytes only under their manifest-recorded digests,
43+
independently of channel, and verify every hit before use. Existing SBOM,
44+
OBOM, attestations, and GitHub logs are the evidence; do not add a parallel
45+
release ledger or result file.
4246
- All first-party and corporate manifest/profile authoring goes through
4347
`capsem-admin`. Corporations select official Capsem packages; they do not
4448
build or replace them.

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed
11+
12+
- Restored fail-closed release inputs and early gates: CI now caches
13+
manifest-selected native profile blobs by recorded digest, installed
14+
Doctor/Winterfell boots real assets with retained failure evidence, blocking
15+
audits/Clippy/frontend checks run before builders, and the frontend uses its
16+
checked-in semantic theme without a Preline dependency.
17+
1018
### Added
1119

1220
- Added fail-closed release glow-up inputs that bind each orthogonal transition

CLAUDE.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ common contract. **Read it before any release work or any change touching
77
logged data** -- it carries the two hard contracts: serialized orthogonal
88
binary/profile releases with complete reusable test modules, and the logger DB
99
boundary (only `capsem-logger` executes ledger queries).
10+
For release inputs, the manifest is the bible: absent means nonexistent.
11+
Mutable manifests are fetched fresh; immutable caches are keyed only by
12+
manifest-recorded artifact digests, never by channel, and reverified on use.
1013

1114
## Quick Start
1215

@@ -15,7 +18,6 @@ just doctor # Check tools (first time)
1518
just doctor fix # Install prerequisites and materialize missing VM assets
1619
just shell # Build + boot VM (~10s)
1720
just smoke # Fast path: doctor + integration tests
18-
just test # Complete local all-artifact proof, including native install glow-up
1921
just test # ALL tests: unit + integration + cross-compile + Docker e2e. No shortcuts.
2022
just release-binaries nightly
2123
just release-profile nightly code
@@ -40,7 +42,7 @@ crates/capsem-tray/ System tray (polls gateway, quick actions)
4042
crates/capsem-proto/ Shared protocol types (host-guest, service-process IPC)
4143
crates/capsem-logger/ Session DB schema, queries, async writer
4244
crates/capsem-guard/ Companion lifecycle primitives (parent-watch + flock singleton)
43-
frontend/ Astro 5 + Svelte 5 + Tailwind v4 + Preline
45+
frontend/ Astro 7 + Svelte 5 + Tailwind v4 + owned semantic CSS
4446
site/ Marketing website (Astro + Svelte 5)
4547
docs/ Documentation site (Astro Starlight)
4648
src/capsem/builder/ capsem-builder CLI (config-driven image builder)
@@ -87,7 +89,7 @@ Skills contain hard-won lessons and project-specific patterns. **Before writing
8789
| Session DB | `/dev-session-debug` | Inspecting session.db, correlating events |
8890
| Benchmarking | `/dev-benchmark` | capsem-bench, performance regression |
8991
| capsem-doctor | `/dev-capsem-doctor` | In-VM diagnostic suite, adding new tests |
90-
| Frontend | `/frontend-design` | UI components, Svelte 5 runes, Tailwind, Preline |
92+
| Frontend | `/frontend-design` | UI components, Svelte 5 runes, Tailwind, owned semantic CSS |
9193
| Build images | `/build-images` | capsem-builder, guest config, rootfs, kernel |
9294
| Initrd repack | `/build-initrd` | Guest binary changes, fast iteration loop |
9395
| Asset pipeline | `/asset-pipeline` | Asset manifest, hash verification, boot-time resolution |

GEMINI.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ binary/profile releases with complete reusable test modules, and the logger DB
99
boundary (only `capsem-logger` executes ledger queries). The only release
1010
commands are `just release-binaries <channel>` and
1111
`just release-profile <channel> <profile>`.
12+
For release inputs, the manifest is the bible: absent means nonexistent.
13+
Mutable manifests are fetched fresh; immutable caches are keyed only by
14+
manifest-recorded artifact digests, never by channel, and reverified on use.
1215

1316
## Skills -- LOAD BEFORE CODING
1417

@@ -30,7 +33,7 @@ Skills contain hard-won lessons and project-specific patterns. **Before writing
3033
| Session DB | `/dev-session-debug` | Inspecting session.db, correlating events |
3134
| Benchmarking | `/dev-benchmark` | capsem-bench, performance regression |
3235
| capsem-doctor | `/dev-capsem-doctor` | In-VM diagnostic suite, adding new tests |
33-
| Frontend | `/frontend-design` | UI components, Svelte 5 runes, Tailwind, Preline |
36+
| Frontend | `/frontend-design` | UI components, Svelte 5 runes, Tailwind, owned semantic CSS |
3437
| Build images | `/build-images` | capsem-builder, guest config, rootfs, kernel |
3538
| Initrd repack | `/build-initrd` | Guest binary changes, fast iteration loop |
3639
| Asset pipeline | `/asset-pipeline` | Asset manifest, hash verification, boot-time resolution |

0 commit comments

Comments
 (0)