border-customs 0.8.1 → 0.8.2
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/README.md +190 -10
- package/dist/assets/gitleaks-defaults-v8.30.1.toml +24 -0
- package/dist/assets/package-lock.json +69 -12
- package/dist/assets/residue-src/crates.ts +60 -31
- package/dist/assets/residue-src/npm.ts +35 -8
- package/dist/assets/residue-src/pypi.ts +31 -11
- package/dist/assets/residue-src/rubygems.ts +43 -20
- package/dist/index.js +2249 -3784
- package/package.json +9 -6
- package/plugin/border.ts +33 -9
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ cd /path/to/your/repo
|
|
|
10
10
|
border check
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
Requires Node >= 22 and the `gitleaks` binary on `PATH` (border vendors the rule config for
|
|
13
|
+
Requires Node >= 22.22.2 (the transitive `ini@7` dependency sets that floor) and the `gitleaks` binary on `PATH` (border vendors the rule config for
|
|
14
14
|
gitleaks 8.30.1; the binary itself is yours to install, same as `git`). secretlint runs
|
|
15
15
|
in-process as a bundled dependency. Each registry leg additionally shells out to its platform's
|
|
16
16
|
own publisher, which must be on `PATH` whenever that target is configured; a missing publisher
|
|
@@ -18,14 +18,29 @@ binary is exit 2, never a skipped leg:
|
|
|
18
18
|
|
|
19
19
|
| Registry target | Publisher border runs | Version the same-bytes proofs were measured on |
|
|
20
20
|
| --- | --- | --- |
|
|
21
|
-
| `npm` | `npm` | (
|
|
21
|
+
| `npm` | `npm` | npm >= 11 for packages with pack-phase hooks (see below) |
|
|
22
22
|
| `pypi` | `python3 -m build` / `python3 -m twine` | (unchanged since 0.1.0) |
|
|
23
23
|
| `crates` | `cargo` | cargo 1.93.1 (rustup) |
|
|
24
24
|
| `rubygems` | `gem` | RubyGems 3.6.7 on ruby 3.3.8 |
|
|
25
25
|
|
|
26
|
+
**npm pack safety probe.** `npm pack --ignore-scripts` is not trustworthy on npm 10: measured
|
|
27
|
+
on npm 10.9.7, the target package's `prepare` script still executes (npm 11.19.1 is clean).
|
|
28
|
+
Before packing, border runs `npm --version`. On npm < 11 it refuses, with a named exit 2, any
|
|
29
|
+
package that declares a `prepack`, `prepare`, or `postpack` script — border never executes the
|
|
30
|
+
code it audits. A package with none of those hooks has nothing for npm to run and stays
|
|
31
|
+
scannable on npm 10. Installing npm >= 11 removes the refusal.
|
|
32
|
+
|
|
26
33
|
Other toolchain versions of `cargo` and `gem` are untested by those byte-determinism proofs.
|
|
27
34
|
Optional engines are listed in [Configuration](#configuration).
|
|
28
35
|
|
|
36
|
+
**Pinned consumption.** Install an exact version (`npm install -g border-customs@<version>`;
|
|
37
|
+
`npx border-customs@<version> check` for a one-off) instead of running gate code out of a
|
|
38
|
+
source checkout. Every check and push record carries `engineBuild` — the identity
|
|
39
|
+
(`<version>+<commit>[.dirty]`) of the border build that produced the verdict, the same string
|
|
40
|
+
`border --version` prints. A `.dirty` suffix means the verdict came from uncommitted code, and
|
|
41
|
+
records from one repo carrying different `engineBuild` values mean the audit trail is mixed:
|
|
42
|
+
both are findings an auditor should chase, which is exactly why the identity is on the record face.
|
|
43
|
+
|
|
29
44
|
## The problem it solves
|
|
30
45
|
|
|
31
46
|
The usual secret workflow is leak-then-repent: `git push`, notice the AWS key in the diff
|
|
@@ -207,7 +222,7 @@ an installer *does*, per tier — the split behind opencode-ai's in-tree `postin
|
|
|
207
222
|
The pairing classes behind these rows (multi-channel PASS **C5** subset/ordering discipline;
|
|
208
223
|
**C9** interpolated-and-indirected root spellings; **C10** comment/quote-boundary shapes that
|
|
209
224
|
once silent-passed) are frozen with their evidence in
|
|
210
|
-
[src/artifacts/RESIDUE-CONTRACT.md](src/artifacts/RESIDUE-CONTRACT.md).
|
|
225
|
+
[src/artifacts/RESIDUE-CONTRACT.md](https://github.com/TachikomaGundam/Border-Customs/blob/main/src/artifacts/RESIDUE-CONTRACT.md).
|
|
211
226
|
|
|
212
227
|
**Fail-closed:** a residue scan whose rule table or classifier sources cannot be read is exit 2,
|
|
213
228
|
never a silent pass — and the classifier source bytes are part of the ledger `rulesHash`, so
|
|
@@ -222,10 +237,30 @@ clean residue scan is an absence of matched signatures, never a certificate of b
|
|
|
222
237
|
The signature table is deliberately closed, and the list of shapes it **cannot see** —
|
|
223
238
|
content-writes, handle-variants, dead spellings, interpolation-then-slash, span-quirk
|
|
224
239
|
over-blocks, IO-instance writers, user-shadowed bare verbs — lives in
|
|
225
|
-
[RESIDUE-CONTRACT.md §8](src/artifacts/RESIDUE-CONTRACT.md); this README points, it does not
|
|
240
|
+
[RESIDUE-CONTRACT.md §8](https://github.com/TachikomaGundam/Border-Customs/blob/main/src/artifacts/RESIDUE-CONTRACT.md); this README points, it does not
|
|
226
241
|
restate. The empirical roundtrip (install → snapshot → uninstall → rc-delta-zero) is the 0.4.0
|
|
227
|
-
valve. **border
|
|
228
|
-
|
|
242
|
+
valve. **border does not execute the code it audits.** Every scan leg (gitleaks, secretlint,
|
|
243
|
+
the native rules, the exfil lens) is pure byte inspection; the cross-channel marker fixture
|
|
244
|
+
(`test/build.execMarkers.test.ts`) pins that a consentless `border check` spawns ZERO build
|
|
245
|
+
toolchains. Registry artifact builds (npm pack, `python -m build`, `gem build`, `cargo
|
|
246
|
+
package`) DO execute repo-supplied build code, so they run only on operator consent:
|
|
247
|
+
`--allow-builds`, or `allowBuilds: true` in the machine store / an explicit `--config` file
|
|
248
|
+
outside the repo (the environment is deliberately NOT a consent source — a hostile `.envrc`
|
|
249
|
+
owns it). Both sources live OUTSIDE the audited tree, and a repo's own border.yaml can declare
|
|
250
|
+
targets but can never enable building them. Without
|
|
251
|
+
consent the run is scan-only: no artifact digests are recorded (visible as MEDIUM
|
|
252
|
+
`build-stage-withheld` findings), and a scan-only PASS can never back a registry publish.
|
|
253
|
+
Consented builds can additionally run inside a **pinned container** (`targets.<ch>.sandboxImage`,
|
|
254
|
+
see Configuration): the container is launched with the network disabled — the `--network none`
|
|
255
|
+
argv the daemon applies is the enforcement anchor, and an in-container probe re-checks DNS and
|
|
256
|
+
TCP from inside as a tripwire — the repo mounted read-only and built from a tmpfs copy, host
|
|
257
|
+
credentials never entering the container, and every ledger record bound to the exact image
|
|
258
|
+
digest that certified its bytes. `sandboxImage` itself is a security-tier key: honored only
|
|
259
|
+
from the machine store or a `--config` file outside the repo whose ownership and modes pass
|
|
260
|
+
the fd-chain qualification, and any competing declaration (repo config, lax-mode file, hijacked
|
|
261
|
+
`XDG_CONFIG_HOME`) is a hard refusal, never a silent fallback. Border is
|
|
262
|
+
containment-by-consent plus optional container containment — it is not a malware sandbox and
|
|
263
|
+
not a VM: a kernel-level escape from the container remains in the threat model.
|
|
229
264
|
|
|
230
265
|
#### Proof valve: `residue.requireProof` (0.4.0)
|
|
231
266
|
|
|
@@ -267,7 +302,7 @@ lives inside. The exfil lens adds five rules over the surfaces about to become p
|
|
|
267
302
|
| `exfil-machine-binding` | vendor inference-model ids pinned on portable surfaces next to model/default/provider context (L-MACHINE-LOCAL; born 2026-10-02) |
|
|
268
303
|
|
|
269
304
|
The severity a reader **observes** is the (rule × facet × channel) matrix, and its single
|
|
270
|
-
home is [src/exfil/severity.ts](src/exfil/severity.ts) — the check pipeline, the
|
|
305
|
+
home is [src/exfil/severity.ts](https://github.com/TachikomaGundam/Border-Customs/blob/main/src/exfil/severity.ts) — the check pipeline, the
|
|
271
306
|
`border exfil` CLI and this table all render that table, never re-decide it; the
|
|
272
307
|
`EXFIL-DOC` guard test fails the build if a cell is restated wrong:
|
|
273
308
|
|
|
@@ -608,11 +643,60 @@ degraded run.
|
|
|
608
643
|
|
|
609
644
|
## Configuration
|
|
610
645
|
|
|
611
|
-
|
|
646
|
+
Border is a property of the **checking machine**, not of the checked repo. Config resolves
|
|
647
|
+
in this order, and the machine-side rungs exist so gate config (including waivers) never has
|
|
648
|
+
to be committed into a product repo:
|
|
649
|
+
|
|
650
|
+
1. `--config <path>` (explicit);
|
|
651
|
+
2. `$BORDER_CONFIG` — fail-closed: set-but-empty or unreadable is exit 2, never a fall-through;
|
|
652
|
+
3. the **machine store**: `$BORDER_CONFIG_DIR` (else `$XDG_CONFIG_HOME/border/machines`, else
|
|
653
|
+
`~/.config/border/machines`) holding `<sha256-16>.yaml` files keyed by the repo's canonical
|
|
654
|
+
remote URL (`host/path`, credentials/`.git`/scp-vs-https spellings collapsed);
|
|
655
|
+
4. `./border.yaml` (cwd, then git toplevel) — kept for repos that *choose* to carry their config;
|
|
656
|
+
5. git-remote inference (targets only, no waivers) when nothing above exists.
|
|
657
|
+
|
|
658
|
+
Unknown keys are
|
|
612
659
|
rejected at load (a typo in a gate config is a gate you did not ask for). `${VAR}`
|
|
613
660
|
expansion applies only to remote URLs and registry/repository/host values, and an unset variable
|
|
614
661
|
is a hard error, never an empty string.
|
|
615
662
|
|
|
663
|
+
#### Sandboxed builds (`targets.<ch>.sandboxImage`)
|
|
664
|
+
|
|
665
|
+
Configure pins with the helper instead of hand-editing the machine store:
|
|
666
|
+
`border sandbox init --lane npm --image node@sha256:<64hex>` (writes only the
|
|
667
|
+
0600 machine-store file under the §3-qualified root, refuses tmp/unowned dirs and
|
|
668
|
+
tag refs); `border sandbox status` shows what the loader will actually honor;
|
|
669
|
+
`unpin` removes keys. The helper never writes into the audited repo.
|
|
670
|
+
|
|
671
|
+
When a lane declares `sandboxImage`, that lane's consented build runs inside `docker run`
|
|
672
|
+
instead of on the host: `--network none` (the daemon-applied argv is the enforcement anchor;
|
|
673
|
+
a DNS+TCP probe re-checks from *inside* as a tripwire that fails the build closed), read-only repo mount, build on a tmpfs snapshot, `--cap-drop ALL`,
|
|
674
|
+
`no-new-privileges`, and a scrubbed env (image defaults + `HOME=/tmp` only). The image MUST be
|
|
675
|
+
digest-pinned:
|
|
676
|
+
|
|
677
|
+
```yaml
|
|
678
|
+
targets:
|
|
679
|
+
npm:
|
|
680
|
+
sandboxImage: node@sha256:<64 hex> # tags are rejected at load — a mutable tag
|
|
681
|
+
# would let check and push certify different bytes
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
`sandboxImage` is a **security-tier key**: it is honored only from the machine store or an
|
|
685
|
+
explicit `--config` file outside the repo, and only after fd-chain qualification (every path
|
|
686
|
+
component verified by open file descriptor: root-owned or euid-owned above your trust anchor,
|
|
687
|
+
euid-owned `0700`-below files `0600` below it — symlink or mode violations fail closed).
|
|
688
|
+
Any other declaration of the same key — the repo's own border.yaml, a lax-mode (group/world
|
|
689
|
+
readable or writable) store file, an `XDG_CONFIG_HOME` override pointing somewhere
|
|
690
|
+
unqualifiable — is a named hard refusal (`sandbox-config-shadowed` /
|
|
691
|
+
`sandbox-config-unqualified`), never a silent ignore and never a host fallback.
|
|
692
|
+
|
|
693
|
+
Freshness and push carry the same binding: a PASS certified inside image X is re-proved only
|
|
694
|
+
inside X (config drift forces a full re-check), and docker being *absent* while an image is
|
|
695
|
+
configured is exit 2 with the remedy named — never a silent host fallback. No `sandboxImage`
|
|
696
|
+
means today's host build, unchanged. The crates lane keeps its registry cache in
|
|
697
|
+
`.border/cache/` (the one writable bind); the pypi image must ship the build backend's
|
|
698
|
+
dependencies (there is no network inside).
|
|
699
|
+
|
|
616
700
|
Minimal, a git-only repo:
|
|
617
701
|
|
|
618
702
|
```yaml
|
|
@@ -663,8 +747,15 @@ rules:
|
|
|
663
747
|
ips: ["192.0.2.1"]
|
|
664
748
|
pathPatterns: ["/Users/*", "*.pfx"]
|
|
665
749
|
maxFileKB: 500 # oversized-file threshold (default)
|
|
750
|
+
aliases: # optional: rule-rename migration for allow pins
|
|
751
|
+
old-rule-name: current-rule-name # {renamed-from: current} — waivers survive renames
|
|
666
752
|
allow: # enumerated suppressions, never blanket
|
|
667
753
|
- { rule: "junk-artifact", match: "*", file: "test/fixtures/**" }
|
|
754
|
+
- rule: "gitleaks:*" # fixture-set waiver: values pins the exact
|
|
755
|
+
file: "tests/fixtures/**" # value digests; ANY value outside stays red
|
|
756
|
+
values: ["<64hex>", "<64hex>"]
|
|
757
|
+
until: "2027-01-01" # optional UTC sunset; after it the entry is
|
|
758
|
+
# inert and echoed as allow-entry-expired
|
|
668
759
|
engines:
|
|
669
760
|
require: [gitleaks, secretlint] # trufflehog: true adds the third-party engine
|
|
670
761
|
residue:
|
|
@@ -675,6 +766,15 @@ release:
|
|
|
675
766
|
|
|
676
767
|
Notes that change behavior:
|
|
677
768
|
|
|
769
|
+
- **Archive member addressing in `allow.file`:** findings inside archives are attributed
|
|
770
|
+
`archive!<inner>`. A plain `file` glob matches only the truncated OUTER path (`archive`),
|
|
771
|
+
so member-level pins need the escape form `archive\\!inner` (the `\!` switches the entry to
|
|
772
|
+
full-attribution matching). Members are addressable; forgetting the escape silently matches
|
|
773
|
+
the whole archive instead.
|
|
774
|
+
- **Waiver floors:** a `values` entry suppresses only the listed value digests — a new value
|
|
775
|
+
under the same path/rule stays red; an `until` entry is inert after its UTC date and is
|
|
776
|
+
echoed as an INFO `allow-entry-expired` finding instead of quietly keeping work.
|
|
777
|
+
|
|
678
778
|
- `targets.git.remotes: []` (explicit, empty) is a *deliberate* repo-local scope: all
|
|
679
779
|
history/tree/identity/artifact legs still run, only the exposure set is empty. A
|
|
680
780
|
completely missing config with real remotes falls back to config-from-`git remote` with
|
|
@@ -719,7 +819,10 @@ the hook must first pass. Drop `--force` to get sub-second skip-ledger replay in
|
|
|
719
819
|
re-scan on every `git push`.
|
|
720
820
|
|
|
721
821
|
**CI.** `border check --json` emits the stable report object; gate on the exit code, parse
|
|
722
|
-
`verdict`/`counts` for dashboards.
|
|
822
|
+
`verdict`/`counts` for dashboards. Each finding is
|
|
823
|
+
`{ rule, severity, target, path?, line?, commit?, engine, message, valueDigest, snippet }` —
|
|
824
|
+
the file location is **`path`** (absent when the finding is commit-only, e.g. an identity
|
|
825
|
+
finding); there is no `file` field. In CI you typically want `--force` on a cache-less
|
|
723
826
|
runner, plus your `gitleaks` binary provisioned in the image (a degraded run exits 2, which
|
|
724
827
|
most CI maps to red; that is the point).
|
|
725
828
|
|
|
@@ -736,7 +839,7 @@ plugin entry ships as `exports["./server"]`):
|
|
|
736
839
|
```jsonc
|
|
737
840
|
{
|
|
738
841
|
// pin the exact version — an @latest channel hits the registry on every cold start
|
|
739
|
-
"plugin": ["border-customs@0.8.
|
|
842
|
+
"plugin": ["border-customs@0.8.2"]
|
|
740
843
|
}
|
|
741
844
|
```
|
|
742
845
|
|
|
@@ -832,6 +935,10 @@ which is now a thin consumer of `inspect --json` with the rc contract unchanged
|
|
|
832
935
|
- **Fail-closed doctrine.** "Silence never means absent" is applied mechanically: empty
|
|
833
936
|
registry stdout, unparsed versions, non-translatable exit codes, unresolvable ownership,
|
|
834
937
|
corrupt-but-present rules inputs, all become exit 2 or a CRITICAL, never a pass.
|
|
938
|
+
- **Platform behaviour is probed, not assumed.** The npm stage reads `npm --version` before
|
|
939
|
+
packing. On npm < 11 a declared pack-phase hook is a named exit 2, because that npm line
|
|
940
|
+
executes `prepare` despite `--ignore-scripts` (reproduced on npm 10.9.7, 2026-10-19); a
|
|
941
|
+
missing or unparseable version is also exit 2.
|
|
835
942
|
- **No telemetry, no callbacks.** `border check` touches the network only for the
|
|
836
943
|
registry pre-flight, against the URLs the channels define: `registry.npmjs.org`,
|
|
837
944
|
`pypi.org`, and `rubygems.org` are overridable (private indexes; `targets.rubygems.host`),
|
|
@@ -843,9 +950,82 @@ which is now a thin consumer of `inspect --json` with the rc contract unchanged
|
|
|
843
950
|
it, and which every scan leg refuses to treat as a finding source or an allow-list
|
|
844
951
|
target. A repo that *tracks* `.border/**` is itself a CRITICAL finding. A single-writer
|
|
845
952
|
lock makes concurrent runs exit 2 instead of racing.
|
|
953
|
+
- **Reports go through a private channel.** See [SECURITY.md](SECURITY.md) for the
|
|
954
|
+
reporting route and scope. Do not put exploit details or live secrets in a public issue.
|
|
955
|
+
|
|
956
|
+
## Development
|
|
957
|
+
|
|
958
|
+
Contributor setup, the exact external-engine list, subset test commands, and the version
|
|
959
|
+
rotation procedure live in [CONTRIBUTING.md](CONTRIBUTING.md). In short:
|
|
960
|
+
|
|
961
|
+
```bash
|
|
962
|
+
npm ci
|
|
963
|
+
npm run typecheck
|
|
964
|
+
npm test
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
CI runs the full suite on Node 22 (npm 10) and Node 24 (npm 11) for every push to `main`
|
|
968
|
+
and every pull request, plus version single-source, typecheck, build, and audit gates.
|
|
846
969
|
|
|
847
970
|
## Changelog
|
|
848
971
|
|
|
972
|
+
### 0.8.2 (2026-11-01)
|
|
973
|
+
- Production dependency graph now measures ZERO advisories (`npm audit --omit=dev`): the
|
|
974
|
+
pattern rule is vendored (`src/engines/borderPatternRule.ts`, MIT attribution; drops the
|
|
975
|
+
unpatchable braces/micromatch + fast-uri chain) and `tool` — an identity function — is
|
|
976
|
+
vendored in `plugin/border.ts`, moving `@opencode-ai/plugin` (and its effect-beta → toml
|
|
977
|
+
chain) to devDependencies; live-host probe tests keep the activation proof. The CI audit
|
|
978
|
+
gate tightens from critical to HIGH so this cannot rot.
|
|
979
|
+
- `border sandbox init|pin|status|unpin` — the opt-in pin helper from the Q1 ruling
|
|
980
|
+
(machine store only, 0600 atomic writes, §3 self-verification with rollback of its own
|
|
981
|
+
writes; deliberately absent from the plugin's agent-reachable command set).
|
|
982
|
+
- Security tier for execution-deciding keys (`src/tier.ts`, sibyl §3⁗/§3⁖/§3‡):
|
|
983
|
+
`sandboxImage`/`allowBuilds` honor only from fd-chain-qualified machine-store or out-of-repo
|
|
984
|
+
`--config` sources; repo declarations, lax-mode files, and hijacked `XDG_CONFIG_HOME` are
|
|
985
|
+
named refusals (`sandbox-config-shadowed`/`sandbox-config-unqualified`); the
|
|
986
|
+
`BORDER_ALLOW_BUILDS` environment channel is REMOVED (never released, so no migration);
|
|
987
|
+
passwd-derived canonical store root — `$HOME` spoofing cannot move it.
|
|
988
|
+
- Sandboxed artifact builds: optional `targets.<ch>.sandboxImage` (digest-pinned, tags fail
|
|
989
|
+
closed at load) runs consented npm/pypi/crates/rubygems builds — and freshness re-packs —
|
|
990
|
+
inside `docker run` with `--network none` proved by an in-container DNS+TCP probe, a
|
|
991
|
+
read-only repo mount, tmpfs build, `--cap-drop ALL`, scrubbed env, and the ledger record
|
|
992
|
+
bound to the exact image digest (a rotated image invalidates cached PASS). Missing docker
|
|
993
|
+
with an image configured is a named exit 2, never a host fallback. New `test/sandbox.test.ts`
|
|
994
|
+
pins the docker argv contract token by token.
|
|
995
|
+
- Hardened the npm pack-phase guard (sibyl must_fix): ALL package.json manifests in the tree
|
|
996
|
+
are scanned, not just the root (a workspaces child's `prepare` is now refused on npm < 11),
|
|
997
|
+
and unreadable manifests or a walk-cap hit count as a hook — unknown is never assumed safe.
|
|
998
|
+
- Machine-side config (HR decoupling handoff 2026-10-23): resolution chain is now
|
|
999
|
+
`--config > $BORDER_CONFIG (fail-closed) > machine store (XDG/border/machines, keyed by
|
|
1000
|
+
canonical remote URL) > ./border.yaml > git-remote inference`, so gate config and waiver
|
|
1001
|
+
lists live on the checking machine and never need to be committed into a product repo.
|
|
1002
|
+
Allow entries gained `values` (fixture-set waivers that never cover a new value), `until`
|
|
1003
|
+
(UTC sunset, expired entries echoed never silently honored), `\!` archive-member escaping,
|
|
1004
|
+
and `rules.aliases` (rule renames no longer strand waivers). Border state was already
|
|
1005
|
+
porcelain-invisible (`.border/.gitignore` self-ignore; verified 2026-10-23).
|
|
1006
|
+
- Provenance: every check and push record carries `engineBuild`
|
|
1007
|
+
(`<version>+<commit>[.dirty]`, the string `border --version` prints), so a verdict names
|
|
1008
|
+
the exact border build that produced it. Motivated by a machine where every gate ran off
|
|
1009
|
+
an unpinned worktree bundle and no record said so; worktree use is now visible on the
|
|
1010
|
+
record face (see "Pinned consumption"). Bundles are stamped by `tools/build.mjs`.
|
|
1011
|
+
- Security (breaking): artifact build stages now require operator consent. A hostile clone can
|
|
1012
|
+
ship its own border.yaml declaring pypi/rubygems targets, and `border check` built them —
|
|
1013
|
+
PEP 517 backends and gemspecs ARE code (`python3 -m build --no-isolation` and `gem build`
|
|
1014
|
+
markers reproduced 2026-10-23). Default runs are now scan-only (zero build spawns, pinned by
|
|
1015
|
+
`test/build.execMarkers.test.ts`); consent comes only from outside the audited tree:
|
|
1016
|
+
`--allow-builds` or `BORDER_ALLOW_BUILDS=1`. A scan-only PASS records no artifact digests and
|
|
1017
|
+
therefore can never back a registry publish; `border scan` of third-party artifacts requires
|
|
1018
|
+
the same consent (named exit 2 without it).
|
|
1019
|
+
- Security: refuse npm < 11 packages that declare `prepack`/`prepare`/`postpack` before
|
|
1020
|
+
spawning `npm pack`. npm 10 executes `prepare` even with `--ignore-scripts` (reproduced on
|
|
1021
|
+
10.9.7; npm 11.19.1 is clean), so the old defense could execute code from the audited repo.
|
|
1022
|
+
The probe also runs before freshness re-packs. New regression tests pin the refusal and the
|
|
1023
|
+
never-fires hook marker.
|
|
1024
|
+
- Fix: the Windows drive-letter path pattern no longer fires on JS escapes in prose
|
|
1025
|
+
(`raw-repoPath:\n`); the UNC pattern no longer spans newlines.
|
|
1026
|
+
- Docs: the `--json` findings schema is stated explicitly (`path`, no `file` alias);
|
|
1027
|
+
npm-target prerequisites now name the npm 11 boundary.
|
|
1028
|
+
|
|
849
1029
|
### 0.8.1 (2026-10-06)
|
|
850
1030
|
- Maintenance release: certificate-chain rebuild off the scrubbed lineage (INCIDENT-20261006
|
|
851
1031
|
identity-exposure cleanup). No functional change vs 0.8.0; 0.8.0's tarball is byte-intact but
|
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
# Vendored from gitleaks v8.30.1 (assets/default_config.toml), MIT License.
|
|
2
|
+
#
|
|
3
|
+
# MIT License
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2019 Zachary Rice
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
|
|
1
25
|
# This file has been auto-generated. Do not edit manually.
|
|
2
26
|
# If you would like to contribute new rules, please use
|
|
3
27
|
# cmd/generate/config/main.go and follow the contributing guidelines
|