From 3561e1edca11df255cafe27804490aa11ee110f2 Mon Sep 17 00:00:00 2001 From: Dotta Date: Wed, 7 Oct 2026 09:41:39 -0500 Subject: [PATCH] ci(hermes): qualify the fixture Node interpreter Remove group/world write bits from the dedicated CI job's Node interpreter, matching the protected paid workflow setup. Preserve the Rust launch verifier and record the first Linux fixture result and interrupted PR checks. Co-Authored-By: Paperclip --- .github/workflows/runner-hermes-native.yml | 11 +++++++++++ doc/plans/2026-10-06-hermes-native-runner.md | 12 ++++++++++++ tests/runner-e2e/workflow-security.test.ts | 2 ++ 3 files changed, 25 insertions(+) diff --git a/.github/workflows/runner-hermes-native.yml b/.github/workflows/runner-hermes-native.yml index c9067f98fa3..0eca7990d31 100644 --- a/.github/workflows/runner-hermes-native.yml +++ b/.github/workflows/runner-hermes-native.yml @@ -46,6 +46,17 @@ jobs: with: version: 9.15.4 + - name: Qualify the job's provider Node interpreter + run: | + node <<'NODE' + const fs = require('node:fs'); + const mode = fs.statSync(process.execPath).mode & 0o777; + fs.chmodSync(process.execPath, mode & ~0o022); + if ((fs.statSync(process.execPath).mode & 0o022) !== 0) { + throw new Error('provider Node interpreter remains group- or world-writable'); + } + NODE + - name: Install workspace dependencies run: | set -euo pipefail diff --git a/doc/plans/2026-10-06-hermes-native-runner.md b/doc/plans/2026-10-06-hermes-native-runner.md index 3285366057a..2c8c665fc23 100644 --- a/doc/plans/2026-10-06-hermes-native-runner.md +++ b/doc/plans/2026-10-06-hermes-native-runner.md @@ -403,6 +403,18 @@ excluding private native homes. Its actual execution result must be checked; the workflow declaration alone is not Linux proof. The protected paid workflow and its default-branch authorization remain unchanged by this addition. +The first Linux CI attempt provisioned the exact pinned closure and passed the +native ACPX fixture in 94.21 seconds, including native command tools, planning, +images, questions, controls, memory and strict recovery. The Rust fixture failed +before native launch because GitHub's Node interpreter was group-writable. +The workflow now removes only group/world write bits from its own interpreter, +matching the existing paid workflow's setup step. The launch verifier is +unchanged; both native fixtures must pass on a new attempt. The corresponding +ordinary PR run recorded a timeout in the unchanged chat retry denial-feedback +browser test, followed by simultaneous runner shutdowns across other jobs. +Their failures remain recorded and need fresh CI. Repository-wide typecheck +and build pass on startup runtime head `2cf45fa7ff52b08215c726cf10b7d8353e69892a`. + The three draft PRs had green CI and fresh Greptile 5/5 at routines `3745f3c5a46bda7778ee132682d1b7ae23b088c1`, native `0dea682031f8e35631faee7a05519ed4dce80d07`, and qualification diff --git a/tests/runner-e2e/workflow-security.test.ts b/tests/runner-e2e/workflow-security.test.ts index 9dd30ccbc90..2ae63104942 100644 --- a/tests/runner-e2e/workflow-security.test.ts +++ b/tests/runner-e2e/workflow-security.test.ts @@ -27,6 +27,8 @@ describe("public repository paid workflow security", () => { expect(fixtures).toContain("PAPERCLIP_HERMES_QUALIFY=1"); expect(fixtures).not.toMatch(/(?:API_KEY|TOKEN|AUTH_JSON|KEEP)/); expect(workflow.indexOf("Provision the pinned Python closure")).toBeLessThan(workflow.indexOf("Run native fixtures")); + expect(workflow.indexOf("Qualify the job's provider Node interpreter")).toBeLessThan(workflow.indexOf("Run native fixtures")); + expect(workflow).toContain("fs.chmodSync(process.execPath, mode & ~0o022)"); expect(workflow).toContain("no paid model, browser or Daytona proof"); const upload = workflow.slice(workflow.indexOf(" - name: Upload fixture evidence")); expect(upload).toContain("hermes-native-evidence/");