Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c56483eb1b |
@@ -33,7 +33,6 @@ export default tseslint.config(
|
||||
'packages/db/vitest.config.ts',
|
||||
'packages/storage/vitest.config.ts',
|
||||
'packages/mosaic/vitest.config.ts',
|
||||
'packages/mosaic/vitest.setup.ts',
|
||||
'packages/mosaic/__tests__/*.ts',
|
||||
'tools/federation-harness/*.ts',
|
||||
],
|
||||
|
||||
@@ -32,10 +32,6 @@ packages/mosaic/framework/tools/tmux/test-send-message-socket.sh | requires a re
|
||||
packages/mosaic/framework/tools/tmux/test-send-message-verdict.sh | requires real tmux-pane fixtures on a throwaway socket; CI image ships no tmux; #1017 burndown (same condition as its sibling)
|
||||
|
||||
# --- single-suite directories: unmeasured in CI ---
|
||||
packages/mosaic/framework/tools/fleet/test-start-agent-session.sh | unmeasured in CI image; stubs tmux via a fake bin dir, likely CI-fit; #1017 burndown
|
||||
packages/mosaic/framework/tools/glpi/test-list-http-status.sh | unmeasured in CI image; stub-based (#807 regression harness), likely CI-fit; #1017 burndown
|
||||
packages/mosaic/framework/tools/orchestrator/test-board-roll.sh | unmeasured in CI image; file-fixture based, likely CI-fit; #1017 burndown
|
||||
packages/mosaic/framework/tools/woodpecker/test-ci-wait-exit-matrix.sh | unmeasured in CI image; drives ci-wait.sh against a stub pipeline-status.sh, likely CI-fit; #1017 burndown
|
||||
|
||||
# --- naming-boundary files the strict test-*.sh prefix cannot even name ---
|
||||
# (#1017: three independent censuses handled the microtest file three different
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"lint": "eslint src",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "vitest run --passWithNoTests && pnpm run test:framework-shell",
|
||||
"test:framework-shell": "bash framework/tools/quality/scripts/check-test-enumeration.sh && bash framework/tools/quality/scripts/test-check-test-enumeration.sh && python3 src/lease-broker/daemon_deadline_unittest.py && python3 src/lease-broker/normative_fragments_unittest.py && python3 src/lease-broker/promotion_binding_unittest.py && python3 src/lease-broker/promotion_trigger_unittest.py && python3 src/lease-broker/receipt_challenge_unittest.py && python3 src/lease-broker/context_recovery_unittest.py && python3 src/lease-broker/recovery_runtime_unittest.py && python3 src/lease-broker/recovery_b1_adversarial_unittest.py && python3 src/lease-broker/receipt_observer_client_unittest.py && python3 src/lease-broker/invariant_r_unittest.py && python3 src/lease-broker/framework_skill_portability_unittest.py && python3 src/mutator-gate/runtime_tools_unittest.py && python3 src/mutator-gate/runtime_launch_guard_unittest.py && python3 src/mutator-gate/version_coupling_unittest.py && python3 framework/tools/lease-broker/check-runtime-launches.py --root ../.. && bash framework/tools/codex/test-pr-diff-context.sh && bash framework/tools/qa/test-deps-preflight.sh && bash framework/tools/git/test-pr-review-gitea-comment.sh && bash framework/tools/git/test-pr-review-repo-host-override.sh && bash framework/tools/git/test-ci-queue-wait-branch-absent.sh && bash framework/tools/git/test-ci-queue-wait-tristate.sh && bash framework/tools/git/test-ci-queue-wait-github-checks.sh && bash framework/tools/git/test-pr-merge-queue-branch.sh && bash framework/tools/git/test-pr-merge-head-pin.sh && bash framework/tools/git/test-pr-merge-message-field.sh && bash framework/tools/git/test-git-credential-mosaic.sh && bash framework/tools/git/test-gitea-token-identity.sh && bash framework/tools/woodpecker/test-terminal-green-contract.sh && bash framework/tools/_scripts/test-install-ordering-guard.sh && bash framework/tools/_scripts/test-mosaic-init-rce.sh && bash framework/tools/tmux/agent-send.test.sh && bash framework/tools/wake/test-wake-store-ack.sh && bash framework/tools/wake/test-wake-store-enqueue-race.sh && bash framework/tools/wake/test-wake-digest-hmac.sh && bash framework/tools/wake/test-wake-digest-quarantine.sh && bash framework/tools/wake/test-wake-detector.sh && bash framework/tools/wake/test-wake-fn-oracle.sh && bash framework/tools/wake/test-wake-reconcile.sh && bash framework/tools/wake/test-wake-beacon.sh && bash framework/tools/wake/test-wake-preimage.sh && bash framework/tools/wake/test-wake-install.sh"
|
||||
"test:framework-shell": "bash framework/tools/quality/scripts/check-test-enumeration.sh && bash framework/tools/quality/scripts/test-check-test-enumeration.sh && python3 src/lease-broker/daemon_deadline_unittest.py && python3 src/lease-broker/normative_fragments_unittest.py && python3 src/lease-broker/promotion_binding_unittest.py && python3 src/lease-broker/promotion_trigger_unittest.py && python3 src/lease-broker/receipt_challenge_unittest.py && python3 src/lease-broker/context_recovery_unittest.py && python3 src/lease-broker/recovery_runtime_unittest.py && python3 src/lease-broker/recovery_b1_adversarial_unittest.py && python3 src/lease-broker/receipt_observer_client_unittest.py && python3 src/lease-broker/invariant_r_unittest.py && python3 src/lease-broker/framework_skill_portability_unittest.py && python3 src/mutator-gate/runtime_tools_unittest.py && python3 src/mutator-gate/runtime_launch_guard_unittest.py && python3 src/mutator-gate/version_coupling_unittest.py && python3 framework/tools/lease-broker/check-runtime-launches.py --root ../.. && bash framework/tools/codex/test-pr-diff-context.sh && bash framework/tools/qa/test-deps-preflight.sh && bash framework/tools/git/test-pr-review-gitea-comment.sh && bash framework/tools/git/test-pr-review-repo-host-override.sh && bash framework/tools/git/test-ci-queue-wait-branch-absent.sh && bash framework/tools/git/test-ci-queue-wait-tristate.sh && bash framework/tools/git/test-ci-queue-wait-github-checks.sh && bash framework/tools/git/test-pr-merge-queue-branch.sh && bash framework/tools/git/test-pr-merge-head-pin.sh && bash framework/tools/git/test-pr-merge-message-field.sh && bash framework/tools/git/test-git-credential-mosaic.sh && bash framework/tools/git/test-gitea-token-identity.sh && bash framework/tools/woodpecker/test-terminal-green-contract.sh && bash framework/tools/_scripts/test-install-ordering-guard.sh && bash framework/tools/_scripts/test-mosaic-init-rce.sh && bash framework/tools/tmux/agent-send.test.sh && bash framework/tools/wake/test-wake-store-ack.sh && bash framework/tools/wake/test-wake-store-enqueue-race.sh && bash framework/tools/wake/test-wake-digest-hmac.sh && bash framework/tools/wake/test-wake-digest-quarantine.sh && bash framework/tools/wake/test-wake-detector.sh && bash framework/tools/wake/test-wake-fn-oracle.sh && bash framework/tools/wake/test-wake-reconcile.sh && bash framework/tools/wake/test-wake-beacon.sh && bash framework/tools/wake/test-wake-preimage.sh && bash framework/tools/wake/test-wake-install.sh && bash framework/tools/fleet/test-start-agent-session.sh && bash framework/tools/glpi/test-list-http-status.sh && bash framework/tools/orchestrator/test-board-roll.sh && bash framework/tools/woodpecker/test-ci-wait-exit-matrix.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mosaicstack/brain": "workspace:*",
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
import { isHostLeaseVariable, scrubHostLeaseEnv } from './host-lease-env.js';
|
||||
|
||||
describe('host lease environment scrubbing', () => {
|
||||
test('removes every lease variable and reports what it removed', () => {
|
||||
const environment = {
|
||||
MOSAIC_LEASE_GENERATION_FILE: '/run/user/1001/mosaic-lease/generation-abc.state',
|
||||
MOSAIC_LEASE_SESSION_ID: 'a'.repeat(64),
|
||||
MOSAIC_LEASE_BROKER_SOCKET: '/run/user/1001/mosaic-lease/broker.sock',
|
||||
MOSAIC_LEASE_RUNTIME: 'claude',
|
||||
MOSAIC_RUNTIME_GENERATION: '388',
|
||||
PATH: '/usr/bin',
|
||||
MOSAIC_AGENT_NAME: 'fred',
|
||||
} as NodeJS.ProcessEnv;
|
||||
|
||||
expect(scrubHostLeaseEnv(environment)).toEqual([
|
||||
'MOSAIC_LEASE_BROKER_SOCKET',
|
||||
'MOSAIC_LEASE_GENERATION_FILE',
|
||||
'MOSAIC_LEASE_RUNTIME',
|
||||
'MOSAIC_LEASE_SESSION_ID',
|
||||
'MOSAIC_RUNTIME_GENERATION',
|
||||
]);
|
||||
expect(environment).toEqual({ PATH: '/usr/bin', MOSAIC_AGENT_NAME: 'fred' });
|
||||
});
|
||||
|
||||
test('a lease variable added later is scrubbed without being listed anywhere', () => {
|
||||
// The prefix rule is the point: this is the case a hand-maintained list would miss.
|
||||
const environment = { MOSAIC_LEASE_SOMETHING_NEW: 'x' } as NodeJS.ProcessEnv;
|
||||
expect(scrubHostLeaseEnv(environment)).toEqual(['MOSAIC_LEASE_SOMETHING_NEW']);
|
||||
expect(environment).toEqual({});
|
||||
});
|
||||
|
||||
test('leaves unrelated variables alone', () => {
|
||||
const environment = {
|
||||
MOSAIC_AGENT_NAME: 'fred',
|
||||
MOSAIC_HOME: '/home/fred/.mosaic',
|
||||
HOME: '/home/fred',
|
||||
} as NodeJS.ProcessEnv;
|
||||
|
||||
expect(scrubHostLeaseEnv(environment)).toEqual([]);
|
||||
expect(environment).toEqual({
|
||||
MOSAIC_AGENT_NAME: 'fred',
|
||||
MOSAIC_HOME: '/home/fred/.mosaic',
|
||||
HOME: '/home/fred',
|
||||
});
|
||||
});
|
||||
|
||||
test('classifies by prefix, not by an exact list', () => {
|
||||
expect(isHostLeaseVariable('MOSAIC_LEASE_ANYTHING')).toBe(true);
|
||||
expect(isHostLeaseVariable('MOSAIC_RUNTIME_GENERATION')).toBe(true);
|
||||
expect(isHostLeaseVariable('MOSAIC_RUNTIME')).toBe(false);
|
||||
expect(isHostLeaseVariable('LEASE_MOSAIC_X')).toBe(false);
|
||||
});
|
||||
|
||||
// Wiring check. On a clean checkout or in CI these variables are unset, so this
|
||||
// passes whether or not vitest.setup.ts is registered -- it is worth little there and
|
||||
// is not claimed to be. Its value is inside a Mosaic-managed agent seat, where the
|
||||
// variables ARE set and this is the assertion that catches the setup file being
|
||||
// dropped from vitest.config.ts. That is the environment the leak was found in.
|
||||
test('the suite does not run with the host lease identity in scope', () => {
|
||||
expect(Object.keys(process.env).filter(isHostLeaseVariable)).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* Remove the host's live lease identity from an environment before tests run.
|
||||
*
|
||||
* The lease specs start their own broker on a private socket and then spawn the real
|
||||
* hook scripts against it, building each child's environment as `{ ...process.env, <the
|
||||
* few vars this case cares about> }`. That spread is the problem: when the suite runs
|
||||
* inside a Mosaic-managed agent seat, `process.env` already carries that seat's real
|
||||
* lease identity, and the parts the spread does not override survive into the child.
|
||||
*
|
||||
* `MOSAIC_LEASE_GENERATION_FILE` is the one that bites. `read_runtime_generation()`
|
||||
* prefers that file over `MOSAIC_RUNTIME_GENERATION`, so a case that carefully sets
|
||||
* `MOSAIC_RUNTIME_GENERATION: '1'` is silently overruled by the host's generation
|
||||
* counter -- which on a long-lived seat is in the hundreds. The revoke client reads it,
|
||||
* sends it, and the test broker advances the session to that generation. Every later
|
||||
* `authorize` in the case sends generation 1, is now behind, and is denied with
|
||||
* `STALE_GENERATION` instead of the `MUTATOR_UNVERIFIED` the case asserts. The gate
|
||||
* still denies, so this is not a hole in the product -- but it turns four acceptance
|
||||
* tests red for a reason that has nothing to do with the code under test.
|
||||
*
|
||||
* It only reproduces inside a managed seat. On a clean checkout or in CI these vars are
|
||||
* unset, the suite is green, and the leak is invisible -- which is why it survived.
|
||||
*
|
||||
* Scrubbing by prefix rather than by an explicit list is deliberate: any lease variable
|
||||
* added later leaks by exactly the same route, and a list would have to be remembered.
|
||||
*/
|
||||
|
||||
const HOST_LEASE_PREFIX = 'MOSAIC_LEASE_';
|
||||
const HOST_LEASE_EXTRA = ['MOSAIC_RUNTIME_GENERATION'];
|
||||
|
||||
export function isHostLeaseVariable(name: string): boolean {
|
||||
return name.startsWith(HOST_LEASE_PREFIX) || HOST_LEASE_EXTRA.includes(name);
|
||||
}
|
||||
|
||||
/** Deletes the host lease variables from `environment`; returns the names removed. */
|
||||
export function scrubHostLeaseEnv(environment: NodeJS.ProcessEnv): string[] {
|
||||
const removed = Object.keys(environment).filter(isHostLeaseVariable);
|
||||
for (const name of removed) {
|
||||
delete environment[name];
|
||||
}
|
||||
return removed.sort();
|
||||
}
|
||||
@@ -5,7 +5,6 @@ export default defineConfig({
|
||||
globals: true,
|
||||
environment: 'node',
|
||||
testTimeout: 30_000,
|
||||
setupFiles: ['./vitest.setup.ts'],
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
include: ['src/commands/skill.ts', 'src/lease-broker/broker-test-client.ts'],
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import { scrubHostLeaseEnv } from './src/test-support/host-lease-env.js';
|
||||
|
||||
// Runs before every spec file in this package. See src/test-support/host-lease-env.ts
|
||||
// for why the host's lease identity must not reach a spawned hook process.
|
||||
scrubHostLeaseEnv(process.env);
|
||||
Reference in New Issue
Block a user