@cosyte/transform 0.0.3 → 0.0.4
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/CHANGELOG.md +115 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,121 @@ this file is maintained by hand (Changesets handles the version bump and publish
|
|
|
12
12
|
The first pre-alpha release (`0.0.1`) will ship the initial public API surface. The package begins
|
|
13
13
|
its public history at `0.0.x`, per the cosyte version ladder (`0.0.x` until first alpha).
|
|
14
14
|
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **The PHI scanner read a symbolic link as clean on BOTH of its enumerating routes, so a link
|
|
18
|
+
under a scan root pointing at a file full of PHI passed the commit gate**
|
|
19
|
+
(`PHI-SCAN-SYMLINK-BLIND-ON-BOTH-ROUTES`; port of the graded fix in `terminology#37`, `5f81640`).
|
|
20
|
+
Measured on this repo's own scanner before the fix, over a link under `src/` pointing at a
|
|
21
|
+
name-bearing synthetic payload: all-mode printed `OK — no hits` and exited **0**, and `--staged`
|
|
22
|
+
did too. The walk enumerates `Dirent.isFile()`, which is an lstat answer, so a link is neither a
|
|
23
|
+
file nor a directory and fell out of the loop whatever it pointed at — and a linked _directory_
|
|
24
|
+
took its whole subtree with it. `--staged` reads content with `git show :<path>`, and git stores a
|
|
25
|
+
link as its **target path** under mode `120000` (`git ls-files --stage` read `120000` on it), so
|
|
26
|
+
that route was handed the path text and never the target's bytes.
|
|
27
|
+
|
|
28
|
+
**The remedy is to narrow the enumeration and follow nothing it enumerates.** Every entry the scan
|
|
29
|
+
enumerates, and every path named directly, is now **refused** if it is not a regular file (exit 2,
|
|
30
|
+
the existing "could not complete" code) rather than being silently skipped. Following such an entry was rejected on purpose: it would read bytes the
|
|
31
|
+
enumeration does not control (outside the repo, a loop, a device, a FIFO that blocks the gate
|
|
32
|
+
forever), and git does not carry those bytes anyway, so a hit on them would be a claim about
|
|
33
|
+
something no commit contains.
|
|
34
|
+
|
|
35
|
+
**The third mode — a named `<path>` — was not blind, and it is fixed in the same pass because the
|
|
36
|
+
invariant has to hold for the whole scanner.** It classified with `statSync`, which
|
|
37
|
+
**dereferences**, so `pnpm phi-scan src/link.ts` read the target's bytes and reported the hits it
|
|
38
|
+
found there, including for a target **outside the repository**. That is never a false clean, which
|
|
39
|
+
is why reading the code does not catch it; it made the scanner's stated rule weaker than one of its
|
|
40
|
+
own routes. It lstats now and refuses through the same closed set. A dangling link is reported as
|
|
41
|
+
the link it is rather than as a missing file, because `existsSync` follows.
|
|
42
|
+
|
|
43
|
+
**Stated precisely, because a looser wording of it was measured false twice: `lstat` answers for
|
|
44
|
+
the final path component only.** A named path whose **ancestor** component is a symlink is still
|
|
45
|
+
followed and still read, and so is a plain absolute or `../` argument. Both predate this change and
|
|
46
|
+
neither is narrowed by it; they are listed with the other residuals below rather than closed,
|
|
47
|
+
because closing them means realpath or containment logic, which is a guard growing past the defect
|
|
48
|
+
it fixes. Neither of the two routes that gate a commit — the pre-commit hook and the walk CI runs —
|
|
49
|
+
reaches either.
|
|
50
|
+
|
|
51
|
+
**`--diff-filter` now admits `T`, and leaving it out is what made the mode check unreachable on a
|
|
52
|
+
tracked file.** Replacing a tracked regular file with a link is neither an add nor a modify:
|
|
53
|
+
measured here, `git diff --cached --raw --diff-filter=AM` printed **nothing** for that change
|
|
54
|
+
while the unfiltered `--raw` printed `:100644 120000 <sha> <sha> T`. Under an `AM` filter the
|
|
55
|
+
record died before any mode could be read and the hook passed a mode-`120000` blob green.
|
|
56
|
+
Admitting `T` also covers the reverse typechange — a tracked link replaced by a real file bearing
|
|
57
|
+
PHI, which is a scan that must happen rather than a refusal. The route reads
|
|
58
|
+
`git diff --cached --raw -z` so the destination mode is visible at all, and a record it cannot
|
|
59
|
+
parse refuses rather than shortening the list silently.
|
|
60
|
+
|
|
61
|
+
**A refusal names every offender by its own repo-relative path plus an engine-owned kind token,
|
|
62
|
+
and never the link target.** A target path is working-tree text that can itself carry PHI — a
|
|
63
|
+
target of the shape `<surname>-<given>-<dob>.txt` is the whole reason, written out as a shape
|
|
64
|
+
rather than an example because a diagnostic about a PHI leak is itself a PHI surface. The scope of
|
|
65
|
+
each route is unchanged: the walk still excludes a gitignored entry (so links get no second,
|
|
66
|
+
stricter boundary of their own) and `--staged` still only looks at `test/fixtures/**` and
|
|
67
|
+
`src/**.ts`. This narrows what those scopes admit; it does not widen them. The walk itself has no
|
|
68
|
+
extension scope — it skips regular `*.md` as documentation and takes everything else — so a link at
|
|
69
|
+
`src/leak.json`, and a linked directory, are refused there too.
|
|
70
|
+
|
|
71
|
+
**Three residuals are disclosed rather than closed** — the ancestor-component and absolute/`../`
|
|
72
|
+
reads above, plus two inherited from the graded reference and
|
|
73
|
+
re-measured here. `R`/`C` rename and copy records are still not enumerated by `--staged` at all —
|
|
74
|
+
admitting them needs the two-path record shape handled, which is a scope decision of its own; the
|
|
75
|
+
stride desync a stray one would cause refuses rather than mis-parses. That residual is reachable by
|
|
76
|
+
an ordinary action rather than only in principle: `git mv` into a scanned prefix raises `R100`,
|
|
77
|
+
which the filter drops, so the pre-commit hook reports clean over a staged PHI-bearing file — on
|
|
78
|
+
the old scanner and on this one alike. The all-mode walk that CI runs does catch it, so the
|
|
79
|
+
exposure is a local commit or a pushed branch, not a merge. And this scanner has no
|
|
80
|
+
refuse-a-scan-that-observed-nothing rule, so an empty enumeration still reports clean.
|
|
81
|
+
|
|
82
|
+
- **The `attw` publish gate passed an untyped pack, so a tarball with no type declarations in it
|
|
83
|
+
would have merged and published as green** (`ATTW-FALSE-GREEN-PORT`; port of the graded fix in
|
|
84
|
+
`terminology#28`, `bf153cb`). `@arethetypeswrong/cli@0.18.4` opens `getExitCode()` with
|
|
85
|
+
`if (!analysis.types) return 0`, returning **before the problem list is read at all** — an untyped
|
|
86
|
+
package is a legitimate npm package, so the CLI treats "no types" as a description rather than a
|
|
87
|
+
problem. No `--profile`, `--ignore-rules` or config setting reaches that early return, which is
|
|
88
|
+
why the remedy is a wrapper (`scripts/attw.mjs`, now what the `attw` script runs) and not a
|
|
89
|
+
stricter invocation. The old invocation here was the bare `attw --pack .`, on the default strict
|
|
90
|
+
profile; it was never lenient.
|
|
91
|
+
|
|
92
|
+
**Reproduced on this package, on a quiet box, with zero concurrency** — both `rm -rf dist && attw
|
|
93
|
+
--pack .` and `pnpm build && rm -f dist/index.d.ts dist/index.d.cts && attw --pack .` print
|
|
94
|
+
"This package does not contain types." and exit **0**. The second is the realistic trigger: `tsup`
|
|
95
|
+
emits the ESM/CJS bundles in one pass and the declarations in a later pass, so **every** build of
|
|
96
|
+
this package has a window where `dist/` holds JS and no `.d.ts`. Polling `dist/` every 5 ms from
|
|
97
|
+
the start of `pnpm build`, that window measured **1,600 ms, 1,646 ms and 2,018 ms** across three
|
|
98
|
+
consecutive builds. Concurrency only widens the window; it is not the defect, and the remedy is
|
|
99
|
+
therefore **not** a lock, a lease or a build queue (umbrella ADR 0015) — the gate is made able to
|
|
100
|
+
report that its own inputs were missing, whatever removed them.
|
|
101
|
+
|
|
102
|
+
Two nets, catching different things. A **preflight** that every relative path `package.json`
|
|
103
|
+
promises (`main`, `module`, `types`, `typings`, every string leaf of `exports` — here
|
|
104
|
+
`./dist/index.{cjs,mjs,d.ts,d.cts}`) exists and is non-empty, which is what catches the build
|
|
105
|
+
window and names the missing file. A **post-check** that promotes `attw`'s untyped sentence to a
|
|
106
|
+
failure, which catches what the preflight structurally cannot: declarations present on disk but
|
|
107
|
+
excluded from the tarball by `files`/`.npmignore`. **No instance of that second case is on record
|
|
108
|
+
in this repo.** Because the post-check reads a printed string it is blindable, so `--quiet`,
|
|
109
|
+
`-f/--format` and `--config-path` are refused **by option name, wholesale, not by value**, along
|
|
110
|
+
with a `.attw.json` setting `quiet` or `format` (`readConfig()` applies those after argv). Three
|
|
111
|
+
of those four routes were measured here to restore the exact exit-0; `--config-path` is refused by
|
|
112
|
+
inference, and says so.
|
|
113
|
+
|
|
114
|
+
`test/scripts/attw-gate.test.ts` pins both nets against the real binary — including the upstream
|
|
115
|
+
exit-0 itself, so an `attw` upgrade that fixes the exit code or rewords the sentence reds the
|
|
116
|
+
suite instead of letting the net go quietly slack — plus a **negative control** on a well-formed
|
|
117
|
+
package and a check that a real `attw` failure still exits with `attw`'s own status. Reducing the
|
|
118
|
+
wrapper back to the bare CLI reds 10 of its 13 tests.
|
|
119
|
+
|
|
120
|
+
**Two limits, stated rather than left to be discovered.** A **complete but stale `dist/`** passes
|
|
121
|
+
both nets; that is not live today only because the verify ladder runs `build` before `attw`. And
|
|
122
|
+
this package's unpublished `@cosyte/fhir` peer (`FHIR-NPM-NAME`, a separate human gate) does not
|
|
123
|
+
change what `--pack .` can see: a good pack reports "No problems found" and exits 0, and does so
|
|
124
|
+
identically with `node_modules/@cosyte/fhir` moved out of the way, so `attw` is not resolving that
|
|
125
|
+
peer either way. Nothing in this entry says a green `attw` speaks to whether a consumer can
|
|
126
|
+
install the peer; it does not.
|
|
127
|
+
|
|
128
|
+
No library code, public API, issue code, mapping or transformed value changes.
|
|
129
|
+
|
|
15
130
|
### Added
|
|
16
131
|
|
|
17
132
|
- **A brand image at the top of `README.md`.** The page opens with the Cosyte lockup, served as a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosyte/transform",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "HL7 v2 → FHIR R4 transformation library for Node.js and TypeScript — IG-grounded, fail-safe, value-free diagnostics; never a confident wrong FHIR value.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"hl7",
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"test:coverage": "vitest run --coverage",
|
|
102
102
|
"clean": "rm -rf dist coverage",
|
|
103
103
|
"pack:docs": "bash scripts/build-docs-artifacts.sh",
|
|
104
|
-
"attw": "attw
|
|
104
|
+
"attw": "node scripts/attw.mjs",
|
|
105
105
|
"version": "changeset version && prettier --write package.json CHANGELOG.md",
|
|
106
106
|
"release": "changeset publish"
|
|
107
107
|
}
|