Repository navigation
v2.8.6 - the apply check now refuses a name ending in a dot or a space
The apply check now refuses a name ending in a dot or a space.
Security
- The final-consent apply check refuses a target name that ends in a dot or a space. Windows strips a trailing dot or space from a path component, so
foo.andfooname one file, and a target spelled with such an ending could be judged under one spelling and written under the other.skills/coalboard/scripts/apply-target.mjsnow refuses, on every platform, a target with a segment below the project root that ends in a dot or a space, with the new reasonname(REFUSE <target> name -); the digest and the report name it as not applicable, like any other refused target, so "apply all" never covers it. The segments of the project root itself are not judged, and..is not treated as a name. That the agent runs the checker is still an instruction it follows, a mitigation and not a guarantee. — test:scripts/lib/apply-target.test.mjs scripts/configure.mjsno longer makes a folder, or writes a config, through a link or junction. Before, a junction or symlink planted at.claudeor.claude/coalin a cloned project made the tool create the config folder at the link's target, outside the project, and write the config there. It now checks the config folder's path first, one component at a time and before it makes any folder: a link or junction on the path is refused wherever it points (even into the project), nothing is made beyond the last checked component, and the tool prints the refusal with a fix (make the path a real folder inside the project, or remove the link) and exits 1. It also refuses to write when the config file itself is a symlink, refuses a legacy config that is a link at the place it is read from, and refuses a link or junction at the<config>.bakname when a backup of a malformed config is due (a link there does not block a write over a valid config); a refusal leaves no.bakbehind. A linked~/.claudefolder still works for--global; a symlink at the global config file itself is refused. The project root is derived from where the config was found, so a config found above the current folder is judged against its own project. Not shipped in the plugin. — test:scripts/configure.test.mjs,scripts/lib/repo-fs.test.mjsscripts/configure.mjswrites the config through a temp file and a rename; not shipped in the plugin. The config is written to a temp file opened exclusively in the config's own folder, then renamed over the target (writeConfigAtomic); a failure leaves the old file untouched, removes the temp file and reports the error, and never falls back to an in-place write. So a link planted at the config file's name after the checks is replaced, not written through, and a process crash leaves the old file or the new one, never a torn one (a power loss is not covered: there is nofsync). It does not close the folder-swap window: a checked folder swapped for a junction before the temp file is made still lands the temp file and the rename outside the project. — test:scripts/configure.test.mjsscripts/configure.mjskeeps the old config file's permission bits when it rewrites the config; not shipped in the plugin. The temp-then-rename write above would otherwise have replaced the file with one made under the default mode, so a config a user had set to0600came back wider. The temp file is now opened with the old file's mode and set to it explicitly (the umask would otherwise narrow it); a first write still takes the default mode. Nothing is claimed here about the.bakcopy's mode: it was not measured on POSIX. — test:scripts/configure.test.mjs
Changed
- Named residual:
configure.mjs's project-config write has a check-to-write window. The tool checks the config folder's path (mkdirRepoParents) and the config file (refuseLinkedTarget) before it makes the missing folders, then writes through a temp file and a rename (writeConfigAtomic). A hostile local process that swaps a checked folder for a junction to outside before the temp file is made can still land the temp file and the rename outside the project. The per-component walk narrows the window; it does not close it. A link planted ahead of time is refused before anything is made.SECURITY.mdnames it. - The canon files are re-copied by blob from the
.githubcanon atbea2b3d; not shipped in the plugin.scripts/lib/wave-run.mjsb60827c6,scripts/lib/wave-run.test.mjsbccbaa58,scripts/release-notes.test.mjsf9dde432,scripts/lib/git-env-census.vectors.mjs6dc3ad82andscripts/verify-release-shape.test.mjs7c2b35c4.NOTICEnow counts as a doc path in the CI and CodeQL doc-only filters and is ignored by the Scorecard trigger, as in the canon.NOTICEitself takes the canon template's wording. - The front-door links workflow is re-copied by blob from the canon at
.github7794678; not shipped in the plugin..github/workflows/front-door-links.ymlis nowf0cc9ec0(was7c582bd7): its job is namedfront-door-linksinstead ofcheck, so it can no longer meet the requiredcheckcontext that belongs tolink-check.yml. — test:scripts/front-door-links.test.mjs