xgauntlet 0.8.3 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +96 -36
  2. package/bin/xgauntlet.js +47 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,7 +5,8 @@
5
5
  <a href="#️-mappestruktur-package-by-feature"><b>🏗️ Mappestruktur</b></a> •
6
6
  <a href="#️-fuld-cli-reference"><b>🛠️ CLI Reference</b></a> •
7
7
  <a href="#-rust-api"><b>🦀 Rust API</b></a> •
8
- <a href="#️-arkitektur-adrs"><b>🏛️ ADRs</b></a>
8
+ <a href="#️-arkitektur-adrs"><b>🏛️ ADRs</b></a> •
9
+ <a href="#-licens"><b>📄 Licens</b></a>
9
10
  </p>
10
11
 
11
12
  ---
@@ -99,7 +100,7 @@ xgauntlet init
99
100
  Når du eller agenten arbejder på en opgave i projektet, afvikles gauntlettet direkte:
100
101
 
101
102
  ```bash
102
- # Kør gauntlet og forseg evidens for en opgave:
103
+ # Kør gauntlet og forsegl evidens for en opgave:
103
104
  xgauntlet verify --task-id 001-bootstrap
104
105
 
105
106
  # Valider kildetræets integritet mod rapporten (drift-kontrol):
@@ -144,8 +145,8 @@ rm -rf ~/.cache/xgauntlet
144
145
  ## 🧭 Pipeline og Gates: Sådan virker det
145
146
 
146
147
  `xGauntlet` arbejder på to adskilte niveauer:
147
- 1. **Metodiske retningslinjer (Agent Skills)**: Proceskrav (såsom sokratisk grilling, TDD-disciplin og arkitektur-review), som agenten instrueres i at følge (`grill-me`, `old-coder`, `code-review`).
148
- 2. **Håndhævede software-gates (CLI & In-Memory WASM)**: Deterministiske kontrolpunkter i Rust-koden (`check-spec`, pre-invocation WASM hook, `verify`, `check-evidence` og `check-release`), der fysisk blokerer uautoriserede handlinger med exit-koder og multi-digest integritetskontrol.
148
+ 1. **Metodiske retningslinjer (Agent Skills)**: Proceskrav (såsom sokratisk behovsafklaring, TDD-disciplin og arkitektur-review), som agenten instrueres i at følge (`discover`, `spec`, `tdd`, `review`, `diagnose`, `release`).
149
+ 2. **Håndhævede software-gates (CLI & In-Memory WASM)**: Deterministiske kontrolpunkter i Rust-koden (`check-spec`, pre-invocation WASM hook, `verify`, `check-evidence`, `check-attestation`, `check-architecture` og `check-release`), der fysisk blokerer uautoriserede handlinger med exit-koder og multi-digest integritetskontrol.
149
150
 
150
151
  > [!NOTE]
151
152
  > **Bemærk om tilstande og Zero-Daemon:** Systemet styres ikke af en global database eller baggrundsdæmon, men af diskrete, uafhængige CLI-kald (`sub-3ms` koldstart). Opgavestatus (`DRAFT`, `ACTIVE`, `PASSED`, `DONE`) er forankret direkte i de enkelte task-filers OKF YAML-frontmatter (`tasks/*.md`), som evalueres on-demand af de respektive gates uden behov for en tilstandsmaskine-service.
@@ -153,33 +154,33 @@ rm -rf ~/.cache/xgauntlet
153
154
  ### Oversigt over udviklingsflowet
154
155
 
155
156
  ```text
156
- [ 1. IDÉAFKLARING ] ──► Metodisk skill (grill-me / grill-with-docs)
157
+ [ 1. IDÉAFKLARING ] ──► Metodisk skill (discover)
157
158
  │ (Opdaterer CONTEXT.md & docs/adr/)
158
159
  ▼
159
160
  [ 2. SPECIFIKATION ] ──► HÅRD GATE: xgauntlet check-spec
160
161
  │ (OKF metadata, formål, kriterier, Must NOT, Aristoteles-glossar)
161
162
  ▼
162
163
  [ 3. TDD & KODNING ] ──► HÅRD GATE: Zero-Ambient-Authority WASM Policy Hook
163
- │ (Kræver aktiv task for beskyttede stier, forhindrer git push)
164
+ │ (Quote-aware tokenization, task scope, forhindrer wrappers & git push)
164
165
  ▼
165
166
  [ 4. FLERLAGS VERIFIKATION ] ──► HÅRD GATE: xgauntlet verify
166
167
  │ (Kører linters, typer, tests; matematisk pre/post manifestkontrol)
167
168
  ▼
168
- [ 5. KODESTANDARD-REVIEW ] ──► Hybrid skill: code-review & udvikleraccept
169
- │ (Audit mod CODING_STANDARDS.md)
169
+ [ 5. KODESTANDARD-REVIEW ] ──► Hybrid skill: review & udvikleraccept
170
+ │ (Audit mod CODING_STANDARDS.md & Fowler smells)
170
171
  ▼
171
- [ 6. DRIFT-KONTROL ] ──► HÅRD GATE: xgauntlet check-evidence
172
- │ (Verificerer at workspace matcher rapporten via Git OID hash)
172
+ [ 6. DRIFT- & ATTESTATION ] ──► HÅRD GATE: xgauntlet check-evidence & check-attestation
173
+ │ (Git OID drift-kontrol og kryptografisk Sigstore OIDC verifikation)
173
174
  ▼
174
- [ 7. RELEASE READINESS ] ──► HÅRD GATE: xgauntlet check-release
175
- (Versionssynkronisering, CHANGELOG.md og ADR-krydsreferencer)
175
+ [ 7. RELEASE READINESS ] ──► HÅRD GATE: xgauntlet check-release (--strict) & release bump
176
+ (WASM-sync, manifest harmony, changelog og transaktionel staging)
176
177
  ```
177
178
 
178
179
  ### Pipelinen trin for trin
179
180
 
180
181
  #### 1. Idé- og kontekstafklaring
181
182
  * **Type**: Metodisk proces (Agent Skill)
182
- * **Hvad der sker**: Før der skrives specifikationer eller kode, aktiveres grilling-skills (`grill-me` eller `grill-with-docs`). Agenten udfordrer antagelser, identificerer risici og afstemmer planer mod eksisterende arkitektur og ADR'er.
183
+ * **Hvad der sker**: Før der skrives specifikationer eller kode, aktiveres sparringsskillen `discover`. Agenten udfordrer antagelser, identificerer risici og afstemmer planer mod eksisterende arkitektur og ADR'er.
183
184
  * **Kontrolpunkt**:
184
185
  * *Hvem godkender*: Udvikleren i direkte dialog.
185
186
  * *Hvordan*: Dialogen udmønter sig i, at agenten opdaterer `CONTEXT.md` og eventuelt udarbejder en ny ADR i `docs/adr/`.
@@ -206,9 +207,10 @@ rm -rf ~/.cache/xgauntlet
206
207
  * *Hvordan*: Agentens værktøjskald (tool calls) overvåges deterministisk ved hvert kald via `xgauntlet hook <harness>`.
207
208
  * *Håndhævelse i koden*:
208
209
  * **Zero Ambient Authority**: WebAssembly-modulet har absolut nul adgang til værtsfilsystem, netværk, systemur eller tilfældighedskilder.
209
- * Beskyttede produktions- og kildestier (`src/`, `tests/`, `crates/`, `packages/`, `.agents/`) kan **ikke** modificeres, medmindre der findes en aktiv task (`tasks/*.md`) med status `ACTIVE`.
210
- * Destruktive kommandoer som `git push`, `git reset --hard`, `git clean -f`, `git branch -D` og `rm -rf /` blokeres hårdt (`reason_code: 4039`).
211
- * Linux Bubblewrap (`bwrap`) er erstattet til fordel for WebAssembly + matematisk invariantkontrol (pre/post manifest-digests i verifikationspipelinen), hvilket sikrer fuld 100% krydsplatform understøttelse på tværs af Linux, macOS og Windows 11 uden kerne-afhængigheder eller root-rettigheder.
210
+ * **Struktureret Command Tokenization**: Shell-kommandoer evalueres via en quote-aware argument-lexer. Eksekverings-wrappers (`env`, `sudo`, `eval`, `bash -c`, `sh -c`, `xargs`, `doas`, `su`, `exec`) afvises fail-closed med `reason_code: 4039`.
211
+ * **Fail-Closed Task Scope**: Filmodifikationer (`WriteFile`) uden for den aktive opgaves erklærede `scope` blokeres hårdt (`reason_code: 4037`). Hvis task scope er udefineret, tillader test-scope isolation udelukkende skrivning til verificerede testfiler.
212
+ * **Destruktiv Beskyttelse**: Destruktive kommandoer som `git push`, `git reset --hard`, `git clean -f`, `git branch -D` og `rm -rf /` blokeres uanset globale flag (`-C`, `-c`, `--no-pager`).
213
+ * **Harness Compliance**: Understøtter officielt fladt `PreInvocation` skema for Google Antigravity og sikker, ikke-destruktiv hook-scaffolding mod JSON-korruption.
212
214
  * *Bemærk om TDD*: Selve rækkefølgen (Red før Green) registreres ikke historisk af test-runneren; det er en metodisk adfærd instrueret via agent-skills.
213
215
 
214
216
  #### 4. Flerlags Verifikation
@@ -225,7 +227,7 @@ rm -rf ~/.cache/xgauntlet
225
227
  #### 5. Review mod Kodestandarder
226
228
  * **Type**: Hybrid gate (Agent Skill + Udvikleraccept)
227
229
  * **Hvad der sker**: Den implementerede løsning auditeres mod arkitekturretningslinjer og regler i `CODING_STANDARDS.md`.
228
- * **Kontrolpunkt**: Standards Review (`code-review` skill)
230
+ * **Kontrolpunkt**: Standards Review (`review` skill)
229
231
  * *Hvem godkender*: Udvikleren assisteret af agentens review-skill.
230
232
  * *Hvordan*: Agenten gennemgår diff'en op mod kodestandarderne og fremhæver eventuelle arkitekturbrud, manglende fejlhåndtering eller navngivningsfejl.
231
233
  * *Håndhævelse i koden*: Gaten er procesmæssig og beror på agentens review-rapport kombineret med udviklerens godkendelse.
@@ -233,24 +235,25 @@ rm -rf ~/.cache/xgauntlet
233
235
  #### 6. Drift- og Integritetskontrol (Two-Tier Model)
234
236
  * **Type**: Hård software-gate
235
237
  * **Hvad der sker**: Verificering af, at kildekoden og arbejdstræet ikke er blevet manipuleret eller er driftet efter testkørslen.
236
- * **Kontrolpunkt**: Drift Verification (`xgauntlet check-evidence`)
237
- * *Hvem godkender*: Drift-detektionsmotoren (`crates/xgauntlet-core/src/features/evidence/drift.rs`).
238
+ * **Kontrolpunkt**: Drift Verification (`xgauntlet check-evidence`) & Attestation Gate (`xgauntlet check-attestation`)
239
+ * *Hvem godkender*: Drift-detektionsmotoren (`crates/xgauntlet-core/src/features/evidence/drift.rs`) og attestation-verifikatoren (`attestation.rs`).
238
240
  * *Hvordan*: Værktøjet genberegner det aktuelle kildetræs workspace-manifest og sammenligner det direkte med værdierne i `verification-report.json`.
239
241
  * *Håndhævelse i koden*:
240
242
  * **Tier 1 (Lokal drift-kontrol)**: Er blot én byte ændret i kildetræ, opgave, config eller politik efter `verify`, afvises tjekket med en specifik `DriftViolation`. Beregningen benytter Git-tree/blob OID-hashes, hvilket gør driftkontrollen fuldstændig immun over for linjeskift-forskelle (LF vs. CRLF) på tværs af styresystemer.
241
- * **Tier 2 (Attestation i CI)**: Jf. [ADR 0005](docs/adr/0005-two-tier-verification-and-attestation-model.md) adskilles lokal verifikation fra uafviselig CI-attestering. I beskyttede CI-miljøer genereres en kryptografisk in-toto/DSSE-attest (Sigstore/OIDC), som forsegler kildens herkomst forud for release.
243
+ * **Tier 2 (Kryptografisk Attestation i CI)**: Jf. [ADR 0005](docs/adr/0005-two-tier-verification-and-attestation-model.md) udstedes der i beskyttede CI-miljøer en kryptografisk in-toto/DSSE-attest (Sigstore/OIDC), som forsegler kildens og binærens herkomst (`attestation.bundle` og `attestation.json`). Denne kan efterprøves lokalt eller remote via `xgauntlet check-attestation`.
242
244
 
243
245
  #### 7. Release Readiness
244
246
  * **Type**: Hård software-gate
245
- * **Hvad der sker**: Koden klargøres til release og merge ved at kontrollere synkronisering mellem versioner, ændringslog og dokumentation.
246
- * **Kontrolpunkt**: Release Gate (`xgauntlet check-release`)
247
+ * **Hvad der sker**: Koden klargøres til release og merge ved at kontrollere synkronisering mellem versioner, ændringslog, WASM-bytecode og dokumentation.
248
+ * **Kontrolpunkt**: Release Gate (`xgauntlet check-release`) & Transaktionel Bump (`xgauntlet release bump`)
247
249
  * *Hvem godkender*: Release-orkestratoren (`crates/xgauntlet-core/src/features/release/engine.rs`).
248
- * *Hvordan*: Værktøjet udfører tre specifikke tjek:
249
- 1. **Versionskonsistens**: Versionsnumre skal matche på tværs af projektets manifests (`Cargo.toml`, `package.json`, `pyproject.toml`).
250
- 2. **Changelog-synkronisering**: `CHANGELOG.md` skal indeholde en sektion for den pågældende version.
251
- 3. **ADR-referencer**: Samtlige ADR-dokumenter i `docs/adr/` skal være eksplicit refereret eller linket i enten `README.md` eller `spec.md`.
252
- * *Håndhævelse i koden*: Returnerer exit-kode 1, hvis der er uoverensstemmelse i versionsnumre, manglende changelog-sektion eller forældreløse ADR-dokumenter.
253
- * *Praktisk udviklerflag*: Med flaget `--allow-unreleased` tillader værktøjet sektionen `[Unreleased]` i `CHANGELOG.md` under løbende udvikling forud for den endelige versions-tagging.
250
+ * *Hvordan*: Værktøjet udfører dybdegående kontroller:
251
+ 1. **Versionskonsistens**: Versionsnumre skal matche på tværs af projektets manifests (`Cargo.toml`, `package.json`, `packages/cli/package.json`).
252
+ 2. **WASM Bytecode Paritet**: Det indlejrede WebAssembly-bytecode valideres mod workspace-versionen (`CONFIG_VERSION_MISMATCH`).
253
+ 3. **Changelog-synkronisering**: `CHANGELOG.md` skal indeholde en sektion for den pågældende version.
254
+ 4. **ADR-referencer**: Samtlige ADR-dokumenter i `docs/adr/` skal være eksplicit refereret eller linket i enten `README.md` eller `spec.md`.
255
+ 5. **Strict Release Mode (`--strict`)**: Validerer rent git-arbejdstræ (med automatisk udelukkelse af cirkulære artefakter) og eksekverer kodeformatering fail-closed.
256
+ 6. **Transaktionel Release Bump**: `xgauntlet release bump [patch|minor|major]` udfører atomisk disk-staging backup (`.xgauntlet_staging_<nonce>`), opdaterer manifests, kompilerer WASM og ruller sikkert tilbage ved fejl uden destruktive git-handlinger.
254
257
 
255
258
  ### 👥 De 4 AI-roller & Session Handoff
256
259
 
@@ -322,7 +325,7 @@ xGauntlet/
322
325
  │
323
326
  └── packages/
324
327
  └── cli/ # NPM distributionspakke (xgauntlet)
325
- └── bin/xgauntlet.js # Zero-dependency platform bootstrapper
328
+ └── bin/xgauntlet.js # Zero-dependency bootstrapper med Sigstore integritetskontrol
326
329
  ```
327
330
 
328
331
  ---
@@ -360,18 +363,64 @@ Mekanisk validering af at opgavespecifikationer indeholder forretningsinvariante
360
363
  xgauntlet check-spec
361
364
  ```
362
365
 
363
- ### 5. Release Readiness (`check-release`)
364
- Validerer at versioner matcher på tværs af manifests (`Cargo.toml`, `package.json`), `CHANGELOG.md` og ADR-krydsreferencer:
366
+ ### 5. Release Readiness Gatekeeper (`check-release`)
367
+ Validerer versionskonsistens, WASM-bytecode synkronisering, `CHANGELOG.md` og ADR-krydsreferencer:
365
368
  ```bash
366
- xgauntlet check-release
369
+ # Standard kørsel under udvikling
370
+ xgauntlet check-release --allow-unreleased
371
+
372
+ # Streng release mode (fail-closed ved uncommitted filer eller formateringsfejl)
373
+ xgauntlet check-release --strict
374
+ ```
375
+
376
+ ### 6. Kryptografisk Attesteringskontrol (`check-attestation`)
377
+ Verificerer Sigstore in-toto/DSSE attesteringsbundter (`attestation.bundle` / `attestation.json`) lokalt eller direkte mod GitHub Releases:
378
+ ```bash
379
+ # Valider lokalt bundt mod release-artefakt
380
+ xgauntlet check-attestation --bundle attestation.bundle --artifact target/release/xgauntlet
381
+
382
+ # Valider remote mod GitHub release med statisk forankret repo-ID (1359184794)
383
+ xgauntlet check-attestation --remote-tag v0.8.4
384
+ ```
385
+
386
+ ### 7. Deklarativ Arkitekturkontrol (`check-architecture`)
387
+ Håndhæver kodestruktur, filstørrelsesgrænser (kildekode max 800 linjer, tests max 1.000 linjer) og forbudte API-tokens:
388
+ ```bash
389
+ xgauntlet check-architecture
390
+ ```
391
+
392
+ ### 8. Transaktionel Versionsstyring (`release bump`)
393
+ Udfører atomisk SemVer opgradering på tværs af manifests, kompilerer og synkroniserer WASM bytecode, roterer CHANGELOG.md og ruller automatisk tilbage ved fejl via disk-staging:
394
+ ```bash
395
+ # Bump patch, minor eller major
396
+ xgauntlet release bump patch
397
+ ```
398
+
399
+ ### 9. Sessions-Overdragelseskort (`handoff`)
400
+ Genererer et standardiseret `🏁 SESSION HANDOFF` telemetrikort til ren kontekstoverdragelse i AI-sessioner:
401
+ ```bash
402
+ xgauntlet handoff --task-id 001-bootstrap
367
403
  ```
368
404
 
369
- ### 6. Workspace Diagnostik (`doctor`)
405
+ ### 10. Workspace Diagnostik (`doctor`)
370
406
  Undersøg workspace-konfiguration, stakke og miljøforudsætninger på tværs af Linux, macOS og Windows:
371
407
  ```bash
372
408
  xgauntlet doctor
373
409
  ```
374
410
 
411
+ ### 11. Global Plugin & Agent Skills Distribution (`plugin install`)
412
+ Installer eller opdater de 6 suveræne agent-skills (`discover`, `spec`, `tdd`, `review`, `diagnose`, `release`) på tværs af opdagede AI agent harnesses:
413
+ ```bash
414
+ # Installer automatisk til alle detekterede agent-harnesses
415
+ xgauntlet plugin install --global
416
+
417
+ # Preview handlinger uden at skrive filer til disk
418
+ xgauntlet plugin install --global --dry-run
419
+
420
+ # Tving overskrivning ved opdatering til ny xgauntlet-version
421
+ xgauntlet plugin install --global --force
422
+ ```
423
+
375
424
  ---
376
425
 
377
426
  ## 🦀 Rust API
@@ -399,13 +448,24 @@ Projektets invariante tekniske valg og designprincipper er dokumenteret i [`docs
399
448
  - 🏛️ **[ADR 0005](docs/adr/0005-two-tier-verification-and-attestation-model.md)**: Two-Tier Verification and Attestation Model
400
449
  - 🏛️ **[ADR 0006](docs/adr/0006-multi-harness-policy-adapter-contract.md)**: Multi-Harness Policy Adapter Contract
401
450
  - 🏛️ **[ADR 0007](docs/adr/0007-local-transparent-supervisor-and-wasm-verifier.md)**: Zero-Daemon WASM Policy Verifier
451
+ - 🏛️ **[ADR 0008](docs/adr/0008-sovereign-agentic-sdlc-task-scoping-and-design-tokens.md)**: Sovereign Agentic SDLC, Task Scoping, and Design Token Governance
402
452
 
403
453
  ---
404
454
 
405
455
  ## 🙏 Anerkendelse & Inspiration (Credits)
406
456
 
407
- `xGauntlet` bygger videre på idéer og pionerarbejde inden for stringent verifikation:
408
- - **[Robert C. Martin ("Uncle Bob")](https://x.com/unclebobmartin/status/2080257779395154409)**: For TDD, Clean Craftsmanship og idéen om at omgive koden med en uomgængelig *gauntlet*.
457
+ `xGauntlet` bygger videre på idéer, filosofi og pionerarbejde inden for stringent software-verifikation, agent-craftsmanship og forsyningskædesikkerhed:
458
+ - **[Robert C. Martin ("Uncle Bob")](https://x.com/unclebobmartin/status/2080257779395154409)**: For TDD, Clean Craftsmanship og princippet om at omgive koden med en uomgængelig, automatiseret *gauntlet*.
409
459
  - **[amazingang (old-coder)](https://github.com/amazingang/old-coder)**: For formuleringen af Evidence-First filosofien (*"Trust moves from inspection to constraints"*).
410
- - **[Matt Pocock](https://github.com/mattpocock)**: For sokratiske workflow-skills (`grill-me`, `grill-with-docs`, `code-review`).
460
+ - **[Matt Pocock](https://github.com/mattpocock)**: For banebrydende arbejde med sokratiske agent-workflows og to-akset review-metodologi.
461
+ - **[Addy Osmani](https://addyosmani.com/)**: For metodiske agent-skills inden for kildestyring under implementering, metodisk forsimpling (*Chesterton's Fence*) og adversarial kvalitets-ratchets.
462
+ - **[Jesse Vincent (obra)](https://github.com/obra/superpowers)**: For Superpowers agent-metodikken, *The Iron Law of Debugging*, anti-goals og deterministisk branch-afslutning.
411
463
  - **[Bytecode Alliance](https://bytecodealliance.org/)**: For Wasmtime og WebAssembly Component Model med formel Zero Ambient Authority.
464
+ - **[Sigstore & OpenSSF](https://sigstore.dev/)**: For keyless OIDC-attestation og in-toto standarder for uafviselig forsyningskædesikkerhed.
465
+
466
+ ---
467
+
468
+ ## 📄 Licens
469
+
470
+ Dette projekt er licenseret under [MIT Licensen](LICENSE).
471
+
package/bin/xgauntlet.js CHANGED
@@ -236,6 +236,34 @@ function findLocalBinary() {
236
236
  return null;
237
237
  }
238
238
 
239
+ export async function fetchAttestationBundle(repo = REPO, version = VERSION, customFetcher = null) {
240
+ const fetchFn = customFetcher || fetch;
241
+ const candidates = [
242
+ `https://github.com/${repo}/releases/download/v${version}/attestation.bundle`,
243
+ `https://github.com/${repo}/releases/download/v${version}/attestation.json`,
244
+ ];
245
+
246
+ let lastStatus = 404;
247
+ let lastStatusText = 'Not Found';
248
+
249
+ for (const url of candidates) {
250
+ try {
251
+ const res = await fetchFn(url, { redirect: 'follow' });
252
+ if (res && res.ok) {
253
+ return await res.json();
254
+ }
255
+ if (res) {
256
+ lastStatus = res.status;
257
+ lastStatusText = res.statusText || 'Not Found';
258
+ }
259
+ } catch (err) {
260
+ lastStatusText = err.message;
261
+ }
262
+ }
263
+
264
+ throw new Error(`HTTP ${lastStatus} fetching attestation bundle: ${lastStatusText}`);
265
+ }
266
+
239
267
  async function downloadAndCacheBinary() {
240
268
  if (process.env.XGAUNTLET_TEST_FORCE_NOT_FOUND === '1') {
241
269
  throw new Error('Forced missing binary for test');
@@ -254,27 +282,22 @@ async function downloadAndCacheBinary() {
254
282
  }
255
283
 
256
284
  const downloadUrl = `https://github.com/${REPO}/releases/download/v${VERSION}/${archiveName}`;
257
- const bundleUrl = `https://github.com/${REPO}/releases/download/v${VERSION}/attestation.bundle`;
258
285
  process.stderr.write(`[xgauntlet] Fetching native engine v${VERSION} for ${platform}-${arch}...\n`);
259
286
 
260
- fs.mkdirSync(cacheDir, { recursive: true });
261
- const tempArchive = path.join(cacheDir, `temp-${Date.now()}-${archiveName}`);
287
+ let tempArchive = null;
288
+ let createdCacheDir = false;
262
289
 
263
290
  try {
264
- const [resArchive, resBundle] = await Promise.all([
291
+ const [resArchive, bundleJson] = await Promise.all([
265
292
  fetch(downloadUrl, { redirect: 'follow' }),
266
- fetch(bundleUrl, { redirect: 'follow' }),
293
+ fetchAttestationBundle(REPO, VERSION),
267
294
  ]);
268
295
 
269
296
  if (!resArchive.ok) {
270
297
  throw new Error(`HTTP ${resArchive.status} fetching binary archive: ${resArchive.statusText}`);
271
298
  }
272
- if (!resBundle.ok) {
273
- throw new Error(`HTTP ${resBundle.status} fetching attestation bundle: ${resBundle.statusText}`);
274
- }
275
299
 
276
300
  const archiveBuffer = Buffer.from(await resArchive.arrayBuffer());
277
- const bundleJson = await resBundle.json();
278
301
 
279
302
  process.stderr.write(`[xgauntlet] Verifying cryptographic release attestation for ${archiveName}...\n`);
280
303
  await verifyReleaseArchive({
@@ -288,6 +311,11 @@ async function downloadAndCacheBinary() {
288
311
  });
289
312
  process.stderr.write(`[xgauntlet] Attestation verified successfully (Repo ID: ${EXPECTED_REPOSITORY_ID}).\n`);
290
313
 
314
+ if (!fs.existsSync(cacheDir)) {
315
+ fs.mkdirSync(cacheDir, { recursive: true });
316
+ createdCacheDir = true;
317
+ }
318
+ tempArchive = path.join(cacheDir, `temp-${Date.now()}-${archiveName}`);
291
319
  fs.writeFileSync(tempArchive, archiveBuffer);
292
320
 
293
321
  if (archiveName.endsWith('.tar.gz')) {
@@ -300,7 +328,7 @@ async function downloadAndCacheBinary() {
300
328
  }
301
329
  }
302
330
 
303
- if (fs.existsSync(tempArchive)) {
331
+ if (tempArchive && fs.existsSync(tempArchive)) {
304
332
  fs.unlinkSync(tempArchive);
305
333
  }
306
334
 
@@ -315,9 +343,17 @@ async function downloadAndCacheBinary() {
315
343
  throw new Error(`Extracted archive did not contain expected binary: ${binName}`);
316
344
  }
317
345
  } catch (err) {
318
- if (fs.existsSync(tempArchive)) {
346
+ if (tempArchive && fs.existsSync(tempArchive)) {
319
347
  try { fs.unlinkSync(tempArchive); } catch {}
320
348
  }
349
+ if (createdCacheDir && fs.existsSync(cacheDir)) {
350
+ try {
351
+ const files = fs.readdirSync(cacheDir);
352
+ if (files.length === 0) {
353
+ fs.rmdirSync(cacheDir);
354
+ }
355
+ } catch {}
356
+ }
321
357
  throw err;
322
358
  }
323
359
  }
package/package.json CHANGED
@@ -38,7 +38,7 @@
38
38
  "test": "node --test"
39
39
  },
40
40
  "type": "module",
41
- "version": "0.8.3",
41
+ "version": "0.8.5",
42
42
  "dependencies": {
43
43
  "sigstore": "^3.1.0"
44
44
  }