mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-17 18:32:19 +02:00
fix(setup,relink): ownership proof has two strengths; weak proof never deletes a directory or discards a differing file
The first #2119 gate treated a byte-identical or banner-bearing real-file SKILL.md as full ownership, so a prefix flip could rm -rf a user's directory (their own qa skill started from a gstack SKILL.md, plus my-templates/) and the link pass could replace their customized file with a symlink. Two strengths now: - STRONG: the .gstack-owned marker (we created the directory), or a directory holding nothing but symlinks and the marker (deleting it loses no data). Only strong proof removes a directory whole. - WEAK: byte-identity with our source or the two-line gen-skill-docs banner on a real file. Weak proof covers that SKILL.md and our runtime-asset links only; a differing file is moved to ${GSTACK_HOME:-~/.gstack}/backups/skills/<ts>/<skill>/ before we link over it, and setup/relink print one summary line naming what moved. The marker is written on every platform now (path-independent proof for Windows copies and for checkouts whose path carries no gstack segment), but only for a directory gstack creates: a directory we merely link into (unclaimed, or a legacy install) never becomes deletable whole. A directory with no SKILL.md at all is unclaimed: the link pass may add our file, the cleanup pass has nothing to remove. Also from the review passes: the banner check reads 8192 bytes, not 40 lines (investigate, office-hours, plan-ceo-review and design-consultation carry the banner past line 40 and were left "foreign" on pre-marker Windows installs); a link into a checkout named without a gstack segment (git worktree add ../gstack-<branch>) is ours when that tree carries setup + VERSION + bin/; relink's fast path is gone so both files canonicalize before judging; relink's root alias (_gstack-command) is gated and stamped like every other entry; relink reports the bare entry name with setup's wording and setup dedupes when forwarding (_run_relink_quiet); the summary names the browser skills as examples. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
953ae675df
commit
73506b59c6
@@ -52,7 +52,18 @@ beforeAll(() => {
|
||||
'SKILL_PREFIX=0',
|
||||
'QUIET=1',
|
||||
'_WINDOWS_COPY_NOTE_PRINTED=1',
|
||||
'_FOREIGN_SKIPPED_ENTRIES=()',
|
||||
`SOURCE_GSTACK_DIR="${ROOT}"`,
|
||||
extractFn('_link_or_copy'),
|
||||
extractFn('_gstack_link_target_abs'),
|
||||
extractFn('_gstack_target_is_ours'),
|
||||
extractFn('_gstack_generated_header'),
|
||||
extractFn('_claude_entry_is_ours'),
|
||||
extractFn('_claude_entry_owned_strongly'),
|
||||
extractFn('_backup_skill_md'),
|
||||
'_BACKED_UP_SKILL_MDS=()',
|
||||
`_SKILL_BACKUP_ROOT="${os.tmpdir()}/gstack-alias-test-backups"`,
|
||||
extractFn('_write_owned_marker'),
|
||||
extractFn('_print_windows_copy_note_once'),
|
||||
extractFn('_link_skill_runtime_assets'),
|
||||
extractFn('link_claude_skill_dirs'),
|
||||
@@ -144,7 +155,15 @@ describe('alias installs are rewritten copies (#2511, #2201)', () => {
|
||||
const script = [
|
||||
'set -e',
|
||||
'IS_WINDOWS=0',
|
||||
'_FOREIGN_SKIPPED_ENTRIES=()',
|
||||
`SOURCE_GSTACK_DIR="${ROOT}"`,
|
||||
extractFn('_link_or_copy'),
|
||||
extractFn('_gstack_link_target_abs'),
|
||||
extractFn('_gstack_target_is_ours'),
|
||||
extractFn('_gstack_generated_header'),
|
||||
extractFn('_claude_entry_is_ours'),
|
||||
extractFn('_claude_entry_owned_strongly'),
|
||||
extractFn('_write_owned_marker'),
|
||||
extractFn('_install_alias_skill_md'),
|
||||
extractFn('link_claude_root_skill_alias'),
|
||||
`link_claude_root_skill_alias "${ROOT}" "${legacyDir}"`,
|
||||
|
||||
Reference in New Issue
Block a user