@afokapu/atdd-bun 0.10.56 → 0.10.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/integrity.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.10.56",
2
+ "version": "0.10.58",
3
3
  "files": {
4
4
  "HOOK_AUDIT.md": "5329d840db37671b1918f688ead26865473b87db73dbc75f7c8b2a8bbe8d6d43",
5
5
  "PLANNER_PORT.md": "fb5935bac8b7ac18994de21e43ace3a5ef8cd55f85b0e3349fca261280054f11",
@@ -1224,7 +1224,7 @@
1224
1224
  "relationships.yaml": "5860a308ebc3ee7fa8172fc2c6633984000ab3003f0ae4b6fa28db48879eda22",
1225
1225
  "src/agent.ts": "6d6c6e75908af8fbab13432f0001b0374bb25cf3dee46ba218dfd67e0090cb56",
1226
1226
  "src/ci.ts": "67e54d2cbfc44a9e42837d5e750af526d6255c539d3c452a4d5fca3226c0d9ac",
1227
- "src/cli.ts": "c4ede85983445a6388bf74bbccf1251dd45df2788a699f1bf2250fa0fda3c516",
1227
+ "src/cli.ts": "90e59edbb8a7ea116ad9e7b4ba56b5c612ac18ada05824e8e941048be4dc72c8",
1228
1228
  "src/docs-capability.ts": "bdeeb414649049b1cd4fa8008cada3a576318be51c43bec91bfa46a8e250c270",
1229
1229
  "src/enforce.ts": "7e6b3a1fc7c90f8e1836ab3e4655778fb569a63be5e7c199de44024fc003e6be",
1230
1230
  "src/hooks.ts": "233d26c0320adea3b315d808811da9b53b989db8effd4f6ed9306a80069101e8",
@@ -1235,7 +1235,7 @@
1235
1235
  "src/planner-schema-validator.ts": "ce529c0936171075e93c7539b3655fe895a98dd2973ebda5775958e6ebc316d9",
1236
1236
  "src/planner-validators.ts": "99adeb65f579af923c11f21a8f55cfb9993b007fd8df59c5f764696b55379cfc",
1237
1237
  "src/profile-registry.ts": "5a7761d324181ae27deb51f198d63648a4c99e858b4de98b54d35e6cf8a39fe7",
1238
- "src/ratchet.ts": "1e90fba040fd90437cd9d0300bcd2dc575a3952a7e5919cc2d5c8ff59814f1f1",
1238
+ "src/ratchet.ts": "16213f88fc09de7911defc185ac6ec45b9ecdfbebbe40a12fb6114fe75e7f896",
1239
1239
  "src/register.ts": "6a2f1c6b8df0dc9c8f45df8ec9fac2be29044e048b08c8ffe423410e94dadedd",
1240
1240
  "src/release.ts": "7b0fe444ee81f476f53b9c21b6c347ef588ee616c60211419cf984132be768ba",
1241
1241
  "src/setup.ts": "38233265afedc63499bbef3b5403889651add335a70efd3813254ba53f4fc4fe",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@afokapu/atdd-bun",
3
- "version": "0.10.56",
3
+ "version": "0.10.58",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/afokapu/atdd-bun.git"
package/src/cli.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env bun
2
2
  import { enforce, enabledProfiles, flowCompatibilityDiagnostic, normalizeProfileName, profileNames, type Profile } from "./enforce";
3
- import { activationContextDigest, compareFindings, contextDigest, isStrictProfileExpansion, parseRatchetPolicy } from "./ratchet";
3
+ import { activationContextDigest, canonicalFindingPath, compareFindings, contextDigest, isStrictProfileExpansion, parseRatchetPolicy } from "./ratchet";
4
4
  import { existsSync } from "node:fs";
5
5
  import { mkdtemp, readFile, rm } from "node:fs/promises";
6
6
  import { tmpdir } from "node:os";
7
- import { join, relative, resolve } from "node:path";
7
+ import { join, resolve } from "node:path";
8
8
  import { finishWorktree, hookEvents, hooksStatus, installHooks, runHook, startWorktree, uninstallHooks, worktreeStatus } from "./hooks";
9
9
  import { ciInit, ciStatus } from "./ci";
10
10
  import { agentInit, agentStatus } from "./agent";
@@ -173,7 +173,7 @@ if (!args.includes("--ratchet")) {
173
173
  if (!(profileActivation ? activationIsValid : ordinaryContextMatches)) { console.error(profileActivation ? "ratchet profile activation requires an explicit monotonic profile expansion and identical non-profile context" : "ratchet base and candidate profile/context differ; use a separately governed adoption path"); process.exitCode = 1; }
174
174
  else {
175
175
  const [baseFindings, candidateFindings] = await Promise.all([enforce({ root: scratch, profiles: candidateProfiles as Profile[] }), enforce({ root: candidateRoot, profiles: candidateProfiles as Profile[] })]);
176
- const normalize = (findings: Awaited<ReturnType<typeof enforce>>, directory: string) => findings.map(finding => ({ ...finding, file: relative(directory, finding.file).replaceAll("\\", "/") }));
176
+ const normalize = (findings: Awaited<ReturnType<typeof enforce>>, directory: string) => findings.map(finding => ({ ...finding, file: canonicalFindingPath(directory, finding.file) }));
177
177
  const delta = compareFindings(normalize(baseFindings, scratch), normalize(candidateFindings, candidateRoot));
178
178
  console.log(JSON.stringify({ schema: "atdd-bun.ratchet-report/v1", mode: policy.mode, base, candidate: (await git(candidateRoot, ["rev-parse", "HEAD"])).out, profiles: stable(candidateProfiles), context: contextDigest(candidateConfig, candidateProfiles), ...delta }, null, 2));
179
179
  if (policy.mode === "reject-new" && delta.new.length) process.exitCode = 1;
package/src/ratchet.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { relative, resolve } from "node:path";
2
+
1
3
  /** Pure v1 primitives for the opt-in exact-base finding ratchet. No baseline is written or accepted. */
2
4
  export type RatchetMode = "report" | "reject-new";
3
5
  export type RatchetPolicy = { mode: RatchetMode; profiles: string[] };
@@ -24,6 +26,14 @@ const normalizedPath = (path: string) => {
24
26
  return normalized;
25
27
  };
26
28
 
29
+ /** Canonicalize a detector location against the root that produced it, refusing traversal and external paths. */
30
+ export function canonicalFindingPath(root: string, path: string): string {
31
+ const supplied = path.replaceAll("\\", "/");
32
+ if (supplied.split("/").includes("..")) throw new Error(`ratchet finding path must be normalized and repository-relative: ${path}`);
33
+ const rootPath = resolve(root), target = resolve(rootPath, path), fromRoot = relative(rootPath, target).replaceAll("\\", "/");
34
+ return normalizedPath(fromRoot);
35
+ }
36
+
27
37
  /** Stable semantic identity: presentation position and rendered evidence deliberately do not participate. */
28
38
  export function findingFingerprint(finding: FindingIdentity): string {
29
39
  const path = normalizedPath(finding.file), subject = finding.subject ?? path;