@vantageos/backend-doctor 0.3.0 → 0.4.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 +15 -6
- package/dist/build-stamp.json +2 -2
- package/dist/coverage.d.ts +1 -1
- package/dist/coverage.js +2 -2
- package/dist/detectors/oracle-axis1.js +1 -1
- package/dist/detectors/source/contract.js +9 -1
- package/dist/detectors/source/credential-hygiene.d.ts +11 -0
- package/dist/detectors/source/credential-hygiene.js +619 -0
- package/dist/detectors/source/isolation-read.d.ts +2 -0
- package/dist/detectors/source/isolation-read.js +557 -0
- package/dist/detectors/source/local-identity.js +6 -1
- package/dist/detectors/source/narrow-then-bound.d.ts +11 -0
- package/dist/detectors/source/narrow-then-bound.js +571 -0
- package/dist/detectors/source/service-account-claim.d.ts +15 -0
- package/dist/detectors/source/service-account-claim.js +491 -0
- package/dist/detectors/standard/_doc.d.ts +1 -1
- package/dist/detectors/standard/_doc.js +2 -2
- package/dist/not-checkable.js +1 -0
- package/dist/registry.d.ts +1 -1
- package/dist/registry.js +29 -1
- package/dist/rule-class.js +2 -2
- package/fixtures/backend-standard-bacc54a.md +785 -0
- package/fixtures/{rule-classes-2825122.json → rule-classes-bacc54a.json} +20 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A conformance instrument. It scores a Convex backend against the **VantagePeers backend standard** — a *pinned, frozen fixture*, not a document authored here — and prints, per rule, the sites that fail it or the sites a human verdict is owed on. It **consumes** the `@vantageos/mcp-doctor` engine (`runDoctor` + `renderTable`) — it never re-implements it and touches no engine file; the contract types are derived from the engine's own signatures.
|
|
4
4
|
|
|
5
|
-
The standard is vendored under `fixtures/backend-standard-<pin>.md`, byte-identical to its upstream git blob; the canonical source lives in ElPi-Corp at `vantagepeers/backend-standard/backend-standard.md` (pin `
|
|
5
|
+
The standard is vendored under `fixtures/backend-standard-<pin>.md`, byte-identical to its upstream git blob; the canonical source lives in ElPi-Corp at `vantagepeers/backend-standard/backend-standard.md` (pin `bacc54a`, 56 rules — on ElPi-Corp `main`; it adds R-54..R-57 and the MCP rule S-28, merged as ElPi-Corp #239 = `7d7df89` before the 2026-10-10 history rewrite, same file blob `85d8530e`; see `PINS.txt`). The doctor never authors the standard — it scores against the frozen copy.
|
|
6
6
|
|
|
7
7
|
## What it checks — every rule, one bucket, derived not typed
|
|
8
8
|
|
|
@@ -21,7 +21,7 @@ The detectors read four kinds of material, each a **comparison target, never an
|
|
|
21
21
|
| oracle-CSV (Axis-2) | the per-tool inventory the target's own `.backend-doctor/vp-by-tool.csv` (or `--oracle <file>`); absent => could-not-judge | R-1..R-13, R-7, R-8, R-37 |
|
|
22
22
|
| writer-tier side-car | `vp-writer-tier.csv` beside the VP oracle (or `--writer-tier <file>`), joined on `outil`; absent => R-10 could-not-judge, file named | R-10 |
|
|
23
23
|
| oracle-CSV (Axis-1) | VP oracle **vs** the VR inventory `.backend-doctor/vr-by-tool.csv` (or `--vr-oracle <file>`) | R-40 |
|
|
24
|
-
| source-tree | the real `convex/` source and `mcp-server/src` (live path, or `fixtures/vp-convex/` in CI) | R-6, R-11, R-16..R-36, R-50..R-
|
|
24
|
+
| source-tree | the real `convex/` source and `mcp-server/src` (live path, or `fixtures/vp-convex/` in CI) | R-6, R-11, R-16..R-36, R-50..R-56 |
|
|
25
25
|
| standard-document | the vendored standard + the four MCP-family docs | R-14, R-15, R-32, R-38, R-39, R-41, R-42 |
|
|
26
26
|
|
|
27
27
|
### The acceptance property — surfacing, not deferring
|
|
@@ -102,14 +102,23 @@ Operator order 2026-10-09: *"No application, no MCP server, and no starter defin
|
|
|
102
102
|
- **R-53 is reused, not re-derived**: its (d) local identity layers, its doors whose principal is resolved by the handler itself, its clause-1 recipient-by-name sites and its (c) master-on-absence branches become CR-2 sites of the matching kind. What R-53 already sanctions (a `getUserIdentity()` value that reaches only a package resolver, the org-ID adapter read) is not a site.
|
|
103
103
|
- **EXEMPT, and reported as exempt**: a file of `@vantageos/cloud-identity` itself, and a site carrying `allow-local-identity: <reason of 8+ characters>` in its leading comment or body. Each exempt site is listed with its reason.
|
|
104
104
|
- **COULD-NOT-JUDGE**: a file with a syntax error is named and judged nowhere (exit 2 when nothing else is red); an empty population is never a clean bill.
|
|
105
|
-
- **Ceiling 0**: CR-2 is mechanical (`fixtures/rule-classes-
|
|
105
|
+
- **Ceiling 0**: CR-2 is mechanical (`fixtures/rule-classes-bacc54a.json`). Any violation is counted in `mechanical_rule_counts` / `mechanical_rule_module_counts` and exits 1.
|
|
106
106
|
|
|
107
|
-
**CR-2 is
|
|
107
|
+
**CR-2 is the standard's R-57, reported under its doctor-owned key.** It was authored before the standard numbered it; the standard at `bacc54a` defines the same rule as R-57. The count stays under the key `CR-2` because the vantage-peers deploy-gate baseline (`.claude/config/backend-doctor-baseline.json`) reads `CR-2`; reporting it under both ids would count one defect as two rules, so R-57 itself is listed under NOT_MECHANICALLY_CHECKABLE with that reason. Renaming the key to `R-57` is a follow-up that must move that baseline in the same delivery. Source and rationale: `src/detectors/source/local-identity.ts`.
|
|
108
108
|
|
|
109
109
|
### R-31 — the read budget of a bulk mutation
|
|
110
110
|
|
|
111
111
|
- **R-31** (`src/detectors/source/readbudget.ts`): a `.collect()` inside a mutation is non-conforming unless it reads an index-equality range carrying `// read-bound: <reason>`; a bounded read (`.take(n)`/`.paginate`) conforms when the mutation self-reschedules with `ctx.scheduler.runAfter`, or when it is a **caller-driven drain** — the `.paginate` result flows to one return statement of the handler itself (a nested callback's return does not count) carrying both the continuation cursor and the `isDone` flag (any field names), so the caller re-invokes it page by page, and no `ctx.runMutation`/`ctx.runAction` in the same transaction carries that cursor or names the mutation; every other bounded read is could-not-judge.
|
|
112
112
|
|
|
113
|
+
### R-54, R-55, R-56 — the door audit's causes 1, 4 and 5
|
|
114
|
+
|
|
115
|
+
Standard `bacc54a` §4. Each is mechanical, has no justification-token exit, and counts in `mechanical_violations`. Their material is the door audit of vantage-peers `16f0907` (`docs/audit/2026-10-09-door-audit.md`, branch `argus/door-audit-16f0907`); the real files are vendored byte-exact in `tests/fixtures/vp-16f0907/` (`.pin`).
|
|
116
|
+
|
|
117
|
+
- **R-54** (`src/detectors/source/service-account-claim.ts`): a public door that resolves its caller through the organisation-scope resolver (`withOrgScope`, or any in-tree function that calls it) must declare a transport-verified claim argument (`verifiedActor` / `verifiedOrg` / `verifiedPerson`) AND refuse the call that is the service account and carries no claim. Red (A): no claim argument. Red (B): a claim argument but no such refusal, so its absence leaves the call master. A refusal is a `throw` (or a refusing `return`) whose path condition holds the service-account state and the claim's absence (a local derived from the claim counts; a refusal of the OTHER population does not). Exits, each listed and none silent: (a) service-account-only (`requireServiceAccount`, or `requireResolvedCaller` with `masterOnly` and `mcpBoundOnly`); (b) callers resolve only through a verified session (`requireOrgAdmin`, a bare identity read) and the door never reaches the scope resolver; (c) `fleet-wide: <reason of 8+ characters>`. Could-not-judge: an action whose scope arrives through a run call, a resolver-shaped callee defined outside the tree, a claim argument spread from a validator the scan cannot find, a door registered through a wrapper. A door that resolves no caller at all is outside the rule (CR-1 / R-6) and not counted. Clause 2 of the rule (the claim confines every row) is a dynamic property and is NOT decided here.
|
|
118
|
+
- **R-55** (`src/detectors/source/narrow-then-bound.ts`): in a public door and the helpers it reaches, a read bounded by `.take`/`.paginate` (or re-bounded by `.slice(0, n)`) whose rows are then narrowed by a caller-dependent predicate (a filter reading the door's arguments or the resolved scope, a `filterBy…` helper, an in-tree helper that narrows its parameter, a loop that skips on such a test) is red. Listed as covered, not silent: a fill loop that holds both the bound and the narrowing, and a refusal on a full window (a throw naming the cap, overflow or truncation) between the latest bound and the narrowing. An unbounded `.collect()` is R-11 / R-47's.
|
|
119
|
+
- **R-56** (`src/detectors/source/credential-hygiene.ts`), four clauses, one site tag each: (1) a credential-named column (`code`, `token`, `secret`, `apiKey`, …) stored without a digest, or a digest of a chosen secret (a door argument named like a secret, an environment secret) that reaches a stored row; (2) a table named like a refresh-token store, read by a hash index, with no function that reads it by hash AND marks the token consumed/revoked or deletes it; (3a) a table whose inserted rows carry `tokenHash` and `expiresAt` with no function that revokes or deletes a row of it, (3b) a mint into such a table (no code or refresh-token linkage) that neither revokes the principal's earlier bearers nor caps them; (4) a request-supplied commit/hash/token identifier matched to stored text by `includes`/`startsWith`/`indexOf` with no 40- or 64-digit check, and (4e) a verification response that echoes stored content. The entropy of an externally generated secret and the binding of a minted bearer to the session's claims are NOT decided here.
|
|
120
|
+
- **R-57** is measured by the doctor-owned CR-2 (`src/detectors/source/local-identity.ts`) and reported under the key `CR-2` (see the CR-2 section). R-57 itself is listed under NOT_MECHANICALLY_CHECKABLE with that reason and is never reported present.
|
|
121
|
+
|
|
113
122
|
### R-52 and R-53 — the write reaches the right row, and the actor is who it is by ID
|
|
114
123
|
|
|
115
124
|
- **R-52** (`src/detectors/source/cross-tenant-write.ts`): a write that reaches a row with no tenant value (no tenant column, or an optional one) through a value the caller chose — an argument, or a stored field a public write set from its arguments, such as `task.project` — must be dominated by a guard reading a server-stamped tenant: the target's own tenant when it has a column, a fleet-only decision when it has none. Tenant columns are the standard's `orgId`/`tenantId`/`workspaceId`/`orgSlug`, or a `namespace` checked against the caller's allowed prefixes (ElPi-Corp #228). The namespace condition is decided per table from its public doors (every query/mutation/action that reads or writes it): every door runs a prefix test (a function taking a namespace parameter and testing it with `.startsWith`, closed over calls — vantage-peers `isNamespaceAllowedForScope` — called on a namespace value: the argument at its namespace parameter derives from `args.namespace`, a row's `.namespace` or a binding of one, never a constant), refuses every non-master, or reads the table only on the true side of an `isMaster` test -> tenant column; no door does -> the table is untenanted; mixed, or no public door -> every R-52 site targeting it is could-not-judge, never green. On vantage-peers `2faa399`, `memories` is mixed (nine doors checked, `oauth.ts:provisionOrganization` reads it through `findSeatNameCollision` unchecked), so its six sites are could-not-judge.
|
|
@@ -134,7 +143,7 @@ It writes exactly `{"sha","cli_commit","convex_path","exit_code","checked","tota
|
|
|
134
143
|
- `mechanical_rule_counts` = an object mapping each red mechanical rule id to its **non-conforming count**, the number its report line prints: sites for a source rule (`R-53: 113 site(s) VIOLATE` -> `"R-53": 113`), rows for an oracle rule (`R-2: 6 of 106 applicable oracle rows VIOLATE` -> `"R-2": 6`), registrations for CR-1, defining functions for CR-2. Its key count equals `mechanical_violations`; `{}` on a clean run. The count is attached by the reduction that formats the printed line, from the same variable (`src/violation-count.ts`), never parsed back from the text. A rule reduced from two red halves (R-31) sums its red halves; a single structural finding (R-14, R-38) counts 1. Printed as `MECHANICAL RULE COUNTS: R-2 6, …` under the MECHANICAL line. **`null`** when `mechanical_violations` is null, or when a red mechanical rule's producer attached no count (printed as `MECHANICAL RULE COUNTS: COULD-NOT-JUDGE — no count attached for …`): a partial map would read as complete.
|
|
135
144
|
- `mechanical_rule_module_counts` = for each **site-based** red mechanical rule (source scans, R-46, CR-1, CR-2), `{ module: count }` summing to that rule's `mechanical_rule_counts` entry. A `convex/` file's module is its basename without extension (`convex/tasks.ts` -> `tasks`, `convex/lib/auth.ts` -> `auth`); a file outside `convex/` keeps its path without extension (R-53 also reads `mcp-server/src`: `mcp-server/src/tools`). Row- and finding-based rules (R-2, R-8, R-13, R-28 and every other oracle rule, R-14, R-37, R-38, R-40, R-41, the standard-document rules) are absent. `null` with `mechanical_rule_counts`.
|
|
136
145
|
|
|
137
|
-
**The class is data, not code.** `fixtures/rule-classes-
|
|
146
|
+
**The class is data, not code.** `fixtures/rule-classes-bacc54a.json` gives every numbered rule plus CR-1 and CR-2 exactly one class with a one-phrase basis (42 mechanical = the standard's 40 + CR-1 + CR-2; 16 judgement = 13 judgement + 3 process). Each R- entry is cross-checked at run time against the pinned standard's own build kind (§15 table, which at `bacc54a` lists all 56 rules; a Detector spec's `*kind:*` token is the fallback for a rule the table omits), `process` mapping to judgement. Consequence: **R-6, R-11, R-29, R-33, R-34, R-35 now COUNT** (ElPi-Corp #225 settled them mechanical), as do **R-52 to R-57**; R-16..R-20 and the other §15 judgement rules print but are not counted, exactly as the standard classifies them.
|
|
138
147
|
|
|
139
148
|
**Never a silent 0.** Abstentions (`could-not-judge`) are not violations: they are listed apart on the MECHANICAL line and keep the exit code at 2 when no violation exists. The count becomes `null` (the hook reads it as INCOMPLETE and refuses) when it cannot be certified: a rule with no class, a sidecar class that contradicts the standard, a sidecar pinned to another standard, incomplete coverage, a failed CRUD self-check, or a judged `convex/` tree that differs from the commit `sha` names. Each reason is printed as `CANNOT CERTIFY: …`.
|
|
140
149
|
|
|
@@ -142,7 +151,7 @@ It writes exactly `{"sha","cli_commit","convex_path","exit_code","checked","tota
|
|
|
142
151
|
|
|
143
152
|
Every input is pinned and, where it is a vendored document, proven byte-identical to its upstream git blob (an un-hashable vendored doc is an authority granted to oneself).
|
|
144
153
|
|
|
145
|
-
**The single authority for which standard fixture is active is the loader constant** `STANDARD_FILE` in [`src/detectors/standard/_doc.ts`](./src/detectors/standard/_doc.ts) — currently `backend-standard-
|
|
154
|
+
**The single authority for which standard fixture is active is the loader constant** `STANDARD_FILE` in [`src/detectors/standard/_doc.ts`](./src/detectors/standard/_doc.ts) — currently `backend-standard-bacc54a.md` (56 rules — adds R-54, a door the service account can reach acts inside a transport-verified organisation and refuses a claimless call; R-55, a read narrows before it bounds; R-56, credentials as digests, single-use refresh tokens, revocable bearers, full-length verification tokens; and R-57, no local identity primitive; canonical source: ElPi-Corp `vantagepeers/backend-standard/backend-standard.md`). `bacc54a` is on ElPi-Corp `main` (`gh api repos/elpiarthera/ElPi-Corp/compare/bacc54a53d5f6f9f20e5254908e2b46807902faa...main` -> ahead, behind 0); the PR #239 merge `7d7df89` carries the same blob but left `main` in the 2026-10-10 history rewrite (`PINS.txt`). The previous pin `backend-standard-2825122.md` (52 rules) and the older ones stay in the tree as provenance. Everything else is provenance, NOT the active pin: `PINS.txt` and any other `fixtures/backend-standard-<sha>.md` still in the tree (e.g. the superseded `backend-standard-a9d7877b.md`, 47 rules — it lacks R-48) are kept only to show what was scored before. If any of them disagrees with `STANDARD_FILE`, `STANDARD_FILE` wins. Read the active pin from `STANDARD_FILE`, never from `PINS.txt` or a number typed elsewhere — following a stale `PINS.txt` would silently score the superseded 47-rule document and never surface R-48. See [`PINS.txt`](./PINS.txt) for the engine, backend snapshot, and MCP-family doc + VR inventory pins.
|
|
146
155
|
|
|
147
156
|
## Discipline (how a detector is proven)
|
|
148
157
|
|
package/dist/build-stamp.json
CHANGED
package/dist/coverage.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* canonical 48-rule standard (51ec7af1) to 2bb402f7, which closes R-7/R-8/R-37/R-40
|
|
5
5
|
* as a written-justification-token control (§23) — the paired standard PR the four
|
|
6
6
|
* decisive detectors below track. Still 48 rules; the pin moves forward with them. */
|
|
7
|
-
export declare const STANDARD_SHA = "
|
|
7
|
+
export declare const STANDARD_SHA = "bacc54a53d5f6f9f20e5254908e2b46807902faa";
|
|
8
8
|
export declare const VENDORED_STANDARD_PATH: string;
|
|
9
9
|
/**
|
|
10
10
|
* Derive the full rule list R-1..R-42 from the VENDORED standard fixture —
|
package/dist/coverage.js
CHANGED
|
@@ -18,8 +18,8 @@ const here = dirname(fileURLToPath(import.meta.url));
|
|
|
18
18
|
* canonical 48-rule standard (51ec7af1) to 2bb402f7, which closes R-7/R-8/R-37/R-40
|
|
19
19
|
* as a written-justification-token control (§23) — the paired standard PR the four
|
|
20
20
|
* decisive detectors below track. Still 48 rules; the pin moves forward with them. */
|
|
21
|
-
export const STANDARD_SHA = "
|
|
22
|
-
export const VENDORED_STANDARD_PATH = join(here, "..", "fixtures", "backend-standard-
|
|
21
|
+
export const STANDARD_SHA = "bacc54a53d5f6f9f20e5254908e2b46807902faa";
|
|
22
|
+
export const VENDORED_STANDARD_PATH = join(here, "..", "fixtures", "backend-standard-bacc54a.md");
|
|
23
23
|
/**
|
|
24
24
|
* Derive the full rule list R-1..R-42 from the VENDORED standard fixture —
|
|
25
25
|
* never typed, never a git show against a local repo. Reads the `**R-NN`
|
|
@@ -31,7 +31,7 @@ export const FIXTURE_VR_ORACLE_PATH = join(here, "..", "..", "fixtures", "vr-by-
|
|
|
31
31
|
* §2 [shared] contract columns are DERIVED from this file, never hardcoded.
|
|
32
32
|
* Defined locally (not imported from coverage.ts) to avoid a registry ↔ coverage
|
|
33
33
|
* import cycle. */
|
|
34
|
-
export const VENDORED_STANDARD_PATH = join(here, "..", "..", "fixtures", "backend-standard-
|
|
34
|
+
export const VENDORED_STANDARD_PATH = join(here, "..", "..", "fixtures", "backend-standard-bacc54a.md");
|
|
35
35
|
/** Load any backend inventory CSV generically from its OWN header — the shared
|
|
36
36
|
* fields are DERIVED from these real headers, never a prose illustration. */
|
|
37
37
|
export function loadInventory(path) {
|
|
@@ -20,6 +20,7 @@ import { existsSync } from "node:fs";
|
|
|
20
20
|
import { join } from "node:path";
|
|
21
21
|
import { siteCount, withCount } from "../../violation-count.js";
|
|
22
22
|
import { hasJustificationTokenInText } from "../oracle-axis2.js";
|
|
23
|
+
import { scanR11UnboundedReads } from "./isolation-read.js";
|
|
23
24
|
/** The standard all four are pinned against (short hash a9d7877b). */
|
|
24
25
|
export const SOURCE_CONTRACT_STANDARD_PIN = "analysis/vantagepeers/backend-standard/backend-standard.md @ a9d7877b4947ed8ae61d234433debb2182a2ba44 (elpiarthera/ElPi-Corp) §15";
|
|
25
26
|
function emptyScan() {
|
|
@@ -179,6 +180,13 @@ export function scanR11(files) {
|
|
|
179
180
|
}
|
|
180
181
|
}
|
|
181
182
|
}
|
|
183
|
+
// The unbounded-read arm (isolation-read.ts): a `.collect()` / `for await` read
|
|
184
|
+
// of a tenant table in a door a non-master caller is served, with no index range
|
|
185
|
+
// on the tenant key. R-55 hands this shape to R-11 by name.
|
|
186
|
+
const unboundedArm = scanR11UnboundedReads(files);
|
|
187
|
+
scan.conform.push(...unboundedArm.conform);
|
|
188
|
+
scan.violate.push(...unboundedArm.violate);
|
|
189
|
+
scan.cnj.push(...unboundedArm.cnj);
|
|
182
190
|
return scan;
|
|
183
191
|
}
|
|
184
192
|
// ---------------------------------------------------------------------------
|
|
@@ -375,7 +383,7 @@ export function scanR26(files) {
|
|
|
375
383
|
function srcDetector(ruleId, id, check, scanFn, emptyReason) {
|
|
376
384
|
return { id, run: (tree) => decide(ruleId, id, check, scanFn(tree.files), emptyReason) };
|
|
377
385
|
}
|
|
378
|
-
export const R11 = srcDetector("R-11", "R-11 tenant isolation is an in-query index predicate, not a post-query filter", "a .filter on a scope key is paired with an adjacent .withIndex/.withSearchIndex .eq on that key", scanR11, "R-11: zero scope-key .filter sites matched in the scanned convex tree — cannot certify the isolation locus. NOT a clean bill.");
|
|
386
|
+
export const R11 = srcDetector("R-11", "R-11 tenant isolation is an in-query index predicate, not a post-query filter", "a .filter on a scope key is paired with an adjacent .withIndex/.withSearchIndex .eq on that key; an unbounded read of a tenant table in a door a non-master caller is served carries the tenant key in its index range", scanR11, "R-11: zero scope-key .filter sites and zero unbounded tenant-table reads matched in the scanned convex tree — cannot certify the isolation locus. NOT a clean bill.");
|
|
379
387
|
export const R24 = srcDetector("R-24", "R-24 filter-selected bulk-write defaults to dry run", "a bulk-write mutation defaults dryRun true and gates apply behind an explicit flag + caller guard", scanR24, "R-24: zero bulk-write mutations matched in the scanned convex tree — cannot certify dry-run-by-default. NOT a clean bill.");
|
|
380
388
|
export const R25 = srcDetector("R-25", "R-25 minted address / cross-boundary bundle org-bound at both ends", "a storage mint or bundle redemption is org-bound by an auth guard; a minted bundle URL expires", scanR25, "R-25: zero storage mint/redemption sites matched (kb*/okfBundle*) — cannot certify org-binding. NOT a clean bill.");
|
|
381
389
|
export const R26 = srcDetector("R-26", "R-26 library-owned component declares its seam boundary", "each app.use(component) seam declares an authority tier + boundary key", scanR26, "R-26: no component mount seam (*.config.ts app.use) found — cannot certify the component seam contract. NOT a clean bill.");
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Detector } from "../../engine-types.js";
|
|
2
|
+
import { type Scan, type SourceDetectorEntry, type SrcFile } from "./_scan.js";
|
|
3
|
+
export declare const R56_ID = "R-56 credentials held as digests of generated secrets, refresh tokens single-use, bearers revocable and session-minted bearers bounded, verification tokens matched in full";
|
|
4
|
+
export declare const R56_STANDARD_PIN = "vantagepeers/backend-standard/backend-standard.md @ bacc54a53d5f6f9f20e5254908e2b46807902faa \u00A74 R-56";
|
|
5
|
+
export interface R56Scan extends Scan {
|
|
6
|
+
/** units read. */
|
|
7
|
+
units: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function scanR56(files: SrcFile[]): R56Scan;
|
|
10
|
+
export declare const R56: Detector;
|
|
11
|
+
export declare const SOURCE_CREDENTIAL_HYGIENE_DETECTORS: SourceDetectorEntry[];
|