mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-27 07:01:54 +02:00
* fix(settings): preserve symlinked settings targets
Resolve the selected target for locking, mutation, backup, and rollback; refuse target changes and preserve private modes. Addresses #2830.
* fix(redact): bind masking to original detected spans
Inspired by #2929's anchored-span diagnosis; independently implemented using normalization offsets. Addresses #2930 and the relocation portion of #2912 without changing detection sensitivity.
* fix(evals): exclude operator credentials from prefix admission
Adapts the credential-suffix screen proposed in #2636, with real launched-child regression coverage and deliberate provider-auth exceptions.
* fix(artifacts): retain custom allowlist rules on reinitialization
Preserve the exact user-owned suffix and publish only a successfully assembled replacement. Independently implements the repair reported in #2907.
* test(cso): verify exact masked reads and unmaskable payload refusal
* fix(cso): preserve exact filesystem identities through lease recovery
Preserve 64-bit device/inode identity and nanosecond race checks. Add native NTFS lifecycle coverage for #2927; retain ambiguous legacy-state refusal without claiming Windows PID-reuse recovery is resolved.
* fix(redact): bind pre-push scans to destination and preserve seam context
Uses #2935 (bd07318) as source evidence for push-target range and slice-overlap defects. Independently implemented; no cherry-pick or release metadata adoption.
* test(ci): gate native agent ownership and settings links on macOS
* fix(browse): bind agent lifetimes and cleanup to owned generations
Uses #2931 by Chris Hutton / Claude Fable 5.1 as attributed design input; independently implemented without broad sweeps or copied code. Keep uncertain children and locks rather than deleting foreign state.
* test(ci): include concurrent shutdown controls in the native macOS gate
* v1.88.1.0 fix: harden credential boundaries and owned state
* fix(redact): preserve target provenance and scan boundary semantics
* test(artifacts): read managed rules from atomic allowlist assembly
* fix: preserve native exit observations and fixture prerequisites
* fix: preserve UTF-16 offsets through redaction normalization
67 lines
2.9 KiB
TypeScript
67 lines
2.9 KiB
TypeScript
import { describe, test, expect } from "bun:test";
|
|
import * as fs from "fs";
|
|
import * as path from "path";
|
|
|
|
const ROOT = path.resolve(import.meta.dir, "..");
|
|
const INIT = fs.readFileSync(path.join(ROOT, "bin", "gstack-artifacts-init"), "utf-8");
|
|
|
|
/** Pull a quoted heredoc body out of gstack-artifacts-init by destination. */
|
|
function heredoc(target: string): string {
|
|
const re = new RegExp(`cat > "${target}" <<'EOF'\\n([\\s\\S]*?)\\nEOF\\n`);
|
|
const m = INIT.match(re);
|
|
if (!m) throw new Error(`heredoc for ${target} not found in gstack-artifacts-init`);
|
|
return m[1];
|
|
}
|
|
|
|
/** fnmatch.fnmatchcase semantics, as compute_paths_to_stage applies them:
|
|
* `*` does not cross a path separator. */
|
|
function globToRe(g: string): RegExp {
|
|
return new RegExp("^" + g.split("*").map((s) => s.replace(/[.]/g, "[.]")).join("[^/]*") + "$");
|
|
}
|
|
|
|
const DECISION_PATHS = [
|
|
"projects/acme-widget/decisions.jsonl",
|
|
"projects/acme-widget/decisions.active.json",
|
|
"projects/acme-widget/decisions.archive.jsonl",
|
|
];
|
|
|
|
/**
|
|
* gstack-decision-log:40 enqueues projects/<slug>/decisions.jsonl after EVERY write,
|
|
* but no managed glob matched it, so compute_paths_to_stage rejected all of them at
|
|
* its "must match at least one allowlist glob" check. The writer and the syncer
|
|
* disagreed silently: turning artifacts sync on backed up learnings, plans, designs
|
|
* and timelines -- everything EXCEPT the durable decision ledger -- and nothing
|
|
* anywhere reported a miss, because a dropped path prints exactly what a synced one
|
|
* does when the queue is otherwise empty.
|
|
*
|
|
* Source-level rather than end-to-end: gstack-artifacts-init.test.ts drives the real
|
|
* script through #!/bin/bash shims and a colon-separated PATH, so it cannot run on
|
|
* Windows -- which is the platform where this bug bit.
|
|
*/
|
|
describe("the artifacts allowlist covers the decision store", () => {
|
|
const globs = heredoc("\\$ALLOWLIST_TMP")
|
|
.split("\n")
|
|
.map((l) => l.trim())
|
|
.filter((l) => l && !l.startsWith("#"));
|
|
|
|
test("every decisions.* path matches at least one allowlist glob", () => {
|
|
for (const p of DECISION_PATHS) {
|
|
expect({ p, matched: globs.some((g) => globToRe(g).test(p)) }).toEqual({ p, matched: true });
|
|
}
|
|
});
|
|
|
|
test("decisions.* are class artifact, so they sync in artifacts-only mode too", () => {
|
|
const map = JSON.parse(heredoc("\\$GSTACK_HOME/\\.brain-privacy-map\\.json"));
|
|
for (const p of DECISION_PATHS) {
|
|
const hit = map.find((e: { pattern: string; class: string }) => globToRe(e.pattern).test(p));
|
|
expect({ p, cls: hit?.class }).toEqual({ p, cls: "artifact" });
|
|
}
|
|
});
|
|
|
|
test("the allowlist still ends with the user-additions marker", () => {
|
|
// Additions below it survive re-init; a glob added above would be silently
|
|
// overwritten the next time gstack-artifacts-init runs.
|
|
expect(heredoc("\\$ALLOWLIST_TMP").trimEnd()).toMatch(/# ---- USER ADDITIONS BELOW ----/);
|
|
});
|
|
});
|