You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The security delta checks package floors (#1769, stage 3): a sixth, offline check package-floor compares the npm packages a range introduced in a lockfile, and a packageManager value changed in a package.json of the range, against the projects-baseline security-floor register scripts/lib/security-floors.json.
The register comes from the host-local baseline. Only when no baseline is configured or it has no register file, the repo register as committed at head is used (scripts/security-floors.json, then scripts/lib/security-floors.json, the copy projects-baseline vendors). Without either the check is skipped / no-register. A configured but unavailable baseline degrades the check (baseline-unavailable) and never falls back to the repo register. It is read only when the range has a candidate.
A version below the floor of its major line is a critical finding with the floor as fixedIn. A bad line or a major older than every registered line is critical without fixedIn. A newer or missing middle line passes. A register older than 30 days degrades the check (stale-register) and keeps its findings.
Under security-delta.mode: strict an introduced package-floor finding with a known floor now blocks the close (exit 3), next to the malicious-package and fixable-critical rules. A finding without a floor only warns.
Register text (source, bad) never reaches findings, reasons, the report or the event. orchestrator.security.delta gains package-floor in checks and by_class.
Discovery probe insecure-infra-defaults (#1770, category infra): runs the baseline's pattern SSOT scripts/check-insecure-defaults.sh --json and reports one medium finding per class and file (today compose-public-port, ssh-host-key-disabled, caddy-panel-public). The probe carries no copy of the patterns; new classes arrive through the SSOT.
The baseline is resolved host-locally only (SO_BASELINE_PATH, then owner.yamlpaths.baseline-path); the scanned repo's config is never read and a baseline inside the scanned repo is rejected. The script runs via execFile without a shell, with the baseline root as cwd and PYTHONSAFEPATH=1.
Without a baseline the probe is skipped / no-baseline. Discovery only, never session-end Phase 2.4. This change adds the probe; it reports no results from other repos.
Every session start checks whether the loaded plugin install can load its runtime dependencies (#1848). The Codex marketplace short form installs each version into a new cache directory without node_modules. Codex reports the plugin installed and enabled, the MCP server answers, and every script that imports js-yaml, zod or another runtime dependency fails (measured 2026-10-28 on 5.14.0: 0 of 11 dependencies in six fresh caches).
A new banner probe, runtime-readiness, checks the plugin root the running hook code was loaded from. So every cache change is re-checked without anyone remembering to. It names the missing packages, the path and the repair command. It imports only node:* modules, starts no process and installs nothing. An unreadable package.json is a degraded warning, never the clean null.
node scripts/runtime-readiness.mjs [--root <dir> | --codex | --claude] [--repair] [--json] checks one install: declared dependencies, two import probes in a fresh child process and the owner-config source (only source/reason, never a value).
Exit codes: 0 ready, 3 not ready, 1 usage or target error, 2 system error.
--repair runs npm ci (or npm install) with --ignore-scripts, adds --omit=dev only outside a git checkout, then re-checks in a new process.
--codex and --claude pick the enabled install, refuse to guess between several, and refuse cache paths that leave the cache directory.
A repeatable install smoke for Claude Code and Codex with a model (#1764). node scripts/install-smoke.mjs --harness <claude|codex|codex-clone> --model <id> installs the plugin from the GitHub mirror into a throwaway profile. It then checks readiness and drives /bootstrap and one feature session through a model endpoint taken from SMOKE_* environment variables, and prints a JSON receipt.
A session passes only at a plan that offers /go, with no project file changed since bootstrap (committed or not) and a successful tool call that opened the session skill. The smoke answers up to three questions with "1", but never past a SEC-008 detector hit.
Keys stay out of every tool call's environment: Claude Code through an apiKeyHelper file, Codex through env_key with SMOKE_* excluded from its tool shells.
The smoke is not a sandbox: the model steps run as the maintainer's OS user. docs/install.md names the residual risk.
The setup docs and the guide record the 2026-10-28 runs on plugin 5.14.0, including a model session (#1764).
Claude Code 2.1.312: install, bootstrap and a session that ends at the plan.
Codex CLI 0.160.1:
The clone installer passes.
The short form needs the repair step.
With gpt-6-sol the session wrote the file without a plan, recorded as model behaviour.
Cursor: a model session needs a Cursor login.
Pi: not installed on the test host.
Found on the way: the telemetry consent question also stops headless claude -p sessions (#1872). A model-chosen command printed the session's own messaging token in 2 of 5 Claude runs (#1873).
Changed
The Claude Code SessionStart hook timeout is 10 s, was 5 s (#1859, reported in GH#76 by dviolante): on a Windows 11 host the first SessionStart ran close to the 5 s limit. SessionEnd already had 10 s. The Codex hooks-codex.json SessionStart timeout is unchanged at 5. Comments and docs/events-schema.md that quoted 5 s now say 10 s.
Fixed
Closed issues no longer keep a status:* label (#1876): issues closed by Closes #N on an MR merge kept their status label, so every label query without a state filter counted wrong (59 "on review" instead of 31). node scripts/lib/issue-close-strip-labels.mjs --strip-closed [--apply] lists every closed issue that still carries any status:* label (labels read from the project's label list, paginated) and, with --apply, removes only those labels and reads the counts back; without --apply it is a dry run. gitlab-ops § Status Labels makes this run part of the check after every merge that closes issues. The one-time sweep on 2026-10-29 cleared 367 closed issues; every status:* label now counts 0 closed issues.
Headless runs are no longer stopped by the telemetry consent question, and the question is English by default (#1872): the SessionStart hook queued the one-time consent nudge for every run outside CI, so claude -p "/session-orchestrator:session …" ended on the question instead of the plan. The hook now treats CI and CLAUDE_CODE_ENTRYPOINT=sdk-* as non-interactive and queues no nudge there. The nudge text follows owner.language (German only for de, English otherwise). Named limit: that the SessionStart hook itself sees sdk-cli under claude -p was measured only for tool child processes.
Session start tells the model to read environment files by key name only (#1873): the instruction "ALWAYS check .env or .env.local" invited unfiltered env, which printed CLAUDE_CODE_MESSAGING_TOKEN in 2 of 5 install-smoke runs. skills/session-start/SKILL.md and the Phase 4 reference now require names, presence or length only (SEC-008), with three safe command forms, and ban cat .env* and bare env/printenv.
Skill snippets start programs through native-command.mjs (#1870, follow-up to #1864): six node -e snippets in skills/ imported node:child_process directly and started git by its bare name, which on Windows can run a git.exe from the user's repo. They now import the drop-ins from scripts/lib/native-command.mjs. A new blocking validate-plugin check, check-skill-child-process.mjs, reports any child_process import inside a fenced code block of skills/**/*.md.