@ploaness/governance 1.0.0
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/LICENSE +21 -0
- package/README.md +13 -0
- package/dist/access-boundary.d.ts +41 -0
- package/dist/access-boundary.d.ts.map +1 -0
- package/dist/access-boundary.js +26 -0
- package/dist/access-boundary.js.map +1 -0
- package/dist/agent-references.d.ts +12 -0
- package/dist/agent-references.d.ts.map +1 -0
- package/dist/agent-references.js +53 -0
- package/dist/agent-references.js.map +1 -0
- package/dist/architecture-layers.d.ts +11 -0
- package/dist/architecture-layers.d.ts.map +1 -0
- package/dist/architecture-layers.js +47 -0
- package/dist/architecture-layers.js.map +1 -0
- package/dist/asset-policy.d.ts +138 -0
- package/dist/asset-policy.d.ts.map +1 -0
- package/dist/asset-policy.js +312 -0
- package/dist/asset-policy.js.map +1 -0
- package/dist/banned-typography.d.ts +13 -0
- package/dist/banned-typography.d.ts.map +1 -0
- package/dist/banned-typography.js +78 -0
- package/dist/banned-typography.js.map +1 -0
- package/dist/bundle-budget.d.ts +16 -0
- package/dist/bundle-budget.d.ts.map +1 -0
- package/dist/bundle-budget.js +37 -0
- package/dist/bundle-budget.js.map +1 -0
- package/dist/commit-message.d.ts +37 -0
- package/dist/commit-message.d.ts.map +1 -0
- package/dist/commit-message.js +144 -0
- package/dist/commit-message.js.map +1 -0
- package/dist/config-references.d.ts +17 -0
- package/dist/config-references.d.ts.map +1 -0
- package/dist/config-references.js +54 -0
- package/dist/config-references.js.map +1 -0
- package/dist/container-failure.d.ts +40 -0
- package/dist/container-failure.d.ts.map +1 -0
- package/dist/container-failure.js +154 -0
- package/dist/container-failure.js.map +1 -0
- package/dist/container-files.d.ts +36 -0
- package/dist/container-files.d.ts.map +1 -0
- package/dist/container-files.js +74 -0
- package/dist/container-files.js.map +1 -0
- package/dist/container-freshness.d.ts +102 -0
- package/dist/container-freshness.d.ts.map +1 -0
- package/dist/container-freshness.js +129 -0
- package/dist/container-freshness.js.map +1 -0
- package/dist/dependency-freshness.d.ts +129 -0
- package/dist/dependency-freshness.d.ts.map +1 -0
- package/dist/dependency-freshness.js +161 -0
- package/dist/dependency-freshness.js.map +1 -0
- package/dist/doc-blocks.d.ts +13 -0
- package/dist/doc-blocks.d.ts.map +1 -0
- package/dist/doc-blocks.js +75 -0
- package/dist/doc-blocks.js.map +1 -0
- package/dist/document-references.d.ts +44 -0
- package/dist/document-references.d.ts.map +1 -0
- package/dist/document-references.js +94 -0
- package/dist/document-references.js.map +1 -0
- package/dist/editorconfig-policy.d.ts +24 -0
- package/dist/editorconfig-policy.d.ts.map +1 -0
- package/dist/editorconfig-policy.js +106 -0
- package/dist/editorconfig-policy.js.map +1 -0
- package/dist/environment-files.d.ts +42 -0
- package/dist/environment-files.d.ts.map +1 -0
- package/dist/environment-files.js +76 -0
- package/dist/environment-files.js.map +1 -0
- package/dist/file-roles.d.ts +39 -0
- package/dist/file-roles.d.ts.map +1 -0
- package/dist/file-roles.js +82 -0
- package/dist/file-roles.js.map +1 -0
- package/dist/generated-denial.d.ts +42 -0
- package/dist/generated-denial.d.ts.map +1 -0
- package/dist/generated-denial.js +87 -0
- package/dist/generated-denial.js.map +1 -0
- package/dist/history-policy.d.ts +32 -0
- package/dist/history-policy.d.ts.map +1 -0
- package/dist/history-policy.js +50 -0
- package/dist/history-policy.js.map +1 -0
- package/dist/image-assets.d.ts +14 -0
- package/dist/image-assets.d.ts.map +1 -0
- package/dist/image-assets.js +205 -0
- package/dist/image-assets.js.map +1 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/install-policy.d.ts +35 -0
- package/dist/install-policy.d.ts.map +1 -0
- package/dist/install-policy.js +61 -0
- package/dist/install-policy.js.map +1 -0
- package/dist/json-shapes.d.ts +86 -0
- package/dist/json-shapes.d.ts.map +1 -0
- package/dist/json-shapes.js +124 -0
- package/dist/json-shapes.js.map +1 -0
- package/dist/license-allowlist.d.ts +15 -0
- package/dist/license-allowlist.d.ts.map +1 -0
- package/dist/license-allowlist.js +157 -0
- package/dist/license-allowlist.js.map +1 -0
- package/dist/network-policy.d.ts +69 -0
- package/dist/network-policy.d.ts.map +1 -0
- package/dist/network-policy.js +173 -0
- package/dist/network-policy.js.map +1 -0
- package/dist/paired-assets.d.ts +34 -0
- package/dist/paired-assets.d.ts.map +1 -0
- package/dist/paired-assets.js +63 -0
- package/dist/paired-assets.js.map +1 -0
- package/dist/payload-access.d.ts +9 -0
- package/dist/payload-access.d.ts.map +1 -0
- package/dist/payload-access.js +168 -0
- package/dist/payload-access.js.map +1 -0
- package/dist/payload-policy.d.ts +18 -0
- package/dist/payload-policy.d.ts.map +1 -0
- package/dist/payload-policy.js +124 -0
- package/dist/payload-policy.js.map +1 -0
- package/dist/payload-source.d.ts +29 -0
- package/dist/payload-source.d.ts.map +1 -0
- package/dist/payload-source.js +84 -0
- package/dist/payload-source.js.map +1 -0
- package/dist/release-age.d.ts +23 -0
- package/dist/release-age.d.ts.map +1 -0
- package/dist/release-age.js +38 -0
- package/dist/release-age.js.map +1 -0
- package/dist/request-limits.d.ts +39 -0
- package/dist/request-limits.d.ts.map +1 -0
- package/dist/request-limits.js +57 -0
- package/dist/request-limits.js.map +1 -0
- package/dist/run-plan.d.ts +32 -0
- package/dist/run-plan.d.ts.map +1 -0
- package/dist/run-plan.js +43 -0
- package/dist/run-plan.js.map +1 -0
- package/dist/run-policy.d.ts +32 -0
- package/dist/run-policy.d.ts.map +1 -0
- package/dist/run-policy.js +37 -0
- package/dist/run-policy.js.map +1 -0
- package/dist/secret-policy.d.ts +13 -0
- package/dist/secret-policy.d.ts.map +1 -0
- package/dist/secret-policy.js +69 -0
- package/dist/secret-policy.js.map +1 -0
- package/dist/settings-layering.d.ts +45 -0
- package/dist/settings-layering.d.ts.map +1 -0
- package/dist/settings-layering.js +134 -0
- package/dist/settings-layering.js.map +1 -0
- package/dist/settings.d.ts +238 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +378 -0
- package/dist/settings.js.map +1 -0
- package/dist/skill-manifest.d.ts +18 -0
- package/dist/skill-manifest.d.ts.map +1 -0
- package/dist/skill-manifest.js +125 -0
- package/dist/skill-manifest.js.map +1 -0
- package/dist/source-text.d.ts +83 -0
- package/dist/source-text.d.ts.map +1 -0
- package/dist/source-text.js +310 -0
- package/dist/source-text.js.map +1 -0
- package/dist/suppression-ceiling.d.ts +48 -0
- package/dist/suppression-ceiling.d.ts.map +1 -0
- package/dist/suppression-ceiling.js +115 -0
- package/dist/suppression-ceiling.js.map +1 -0
- package/dist/tailwind-tokens.d.ts +16 -0
- package/dist/tailwind-tokens.d.ts.map +1 -0
- package/dist/tailwind-tokens.js +70 -0
- package/dist/tailwind-tokens.js.map +1 -0
- package/dist/text-escapes.d.ts +7 -0
- package/dist/text-escapes.d.ts.map +1 -0
- package/dist/text-escapes.js +14 -0
- package/dist/text-escapes.js.map +1 -0
- package/dist/toolchain-pins.d.ts +42 -0
- package/dist/toolchain-pins.d.ts.map +1 -0
- package/dist/toolchain-pins.js +99 -0
- package/dist/toolchain-pins.js.map +1 -0
- package/dist/url-safety.d.ts +12 -0
- package/dist/url-safety.d.ts.map +1 -0
- package/dist/url-safety.js +58 -0
- package/dist/url-safety.js.map +1 -0
- package/dist/version-policy.d.ts +99 -0
- package/dist/version-policy.d.ts.map +1 -0
- package/dist/version-policy.js +306 -0
- package/dist/version-policy.js.map +1 -0
- package/dist/vulnerability-policy.d.ts +66 -0
- package/dist/vulnerability-policy.d.ts.map +1 -0
- package/dist/vulnerability-policy.js +106 -0
- package/dist/vulnerability-policy.js.map +1 -0
- package/dist/wiring-policy.d.ts +226 -0
- package/dist/wiring-policy.d.ts.map +1 -0
- package/dist/wiring-policy.js +458 -0
- package/dist/wiring-policy.js.map +1 -0
- package/dist/wiring-violation.d.ts +6 -0
- package/dist/wiring-violation.d.ts.map +1 -0
- package/dist/wiring-violation.js +8 -0
- package/dist/wiring-violation.js.map +1 -0
- package/dist/workspace-policy.d.ts +177 -0
- package/dist/workspace-policy.d.ts.map +1 -0
- package/dist/workspace-policy.js +228 -0
- package/dist/workspace-policy.js.map +1 -0
- package/dist/yaml-blocks.d.ts +43 -0
- package/dist/yaml-blocks.d.ts.map +1 -0
- package/dist/yaml-blocks.js +87 -0
- package/dist/yaml-blocks.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-policy.js","sourceRoot":"","sources":["../src/install-policy.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,EAAE;AACF,oGAAoG;AACpG,mGAAmG;AACnG,uGAAuG;AACvG,uFAAuF;AACvF,EAAE;AACF,yGAAyG;AACzG,sGAAsG;AACtG,UAAU;AACV,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAE9E;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAsB;IAC9C,WAAW;IACX,aAAa;IACb,qBAAqB;IACrB,mBAAmB;CACpB,CAAA;AAED,0EAA0E;AAC1E,MAAM,aAAa,GAAW,uBAAuB,CAAA;AAErD,uGAAuG;AACvG,MAAM,cAAc,GAAsB,CAAC,YAAY,EAAE,aAAa,CAAC,CAAA;AAUvE;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,aAAqB,EAA4B,EAAE,CAC/E,aAAa,CAAC,OAAO,CAAC,CAAC,GAAW,EAA4B,EAAE,CAC9D,sBAAsB,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,GAAG,CAC5C,CAAC,CAAC,WAAW,EAAE,SAAS,CAA4B,EAAiB,EAAE,CAAC,CAAC;IACvE,GAAG;IACH,WAAW;IACX,SAAS;CACV,CAAC,CACH,CACF,CAAA;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAC5C,aAAqB,EACrB,WAAoB,EACX,EAAE;IACX,IAAI,mBAAmB,CAAC,aAAa,EAAE,aAAa,CAAC,EAAE,CAAC;QACtD,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC,CAAA;AAC5E,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,WAAoB,EAAqB,EAAE;IAChF,MAAM,WAAW,GAAY,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,aAAa,CAAC,CAAA;IACjF,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC,GAAW,EAAW,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;AAClG,CAAC,CAAA"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/** A parsed document, or the reason it could not be parsed. */
|
|
2
|
+
export interface ParsedJson {
|
|
3
|
+
readonly value: unknown;
|
|
4
|
+
/** Undefined when the text parsed; the parser's own message otherwise. */
|
|
5
|
+
readonly problem: string | undefined;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Parse JSON that may carry comments and trailing commas.
|
|
9
|
+
*
|
|
10
|
+
* `tsconfig.json` legally carries both, and so does a Biome config - which meant the rules that judge
|
|
11
|
+
* them threw a SyntaxError out of a pure function on a project scaffolded by `create-payload-app`. The
|
|
12
|
+
* gate that caught it is a precondition, so the whole run halted saying only that the gate "could not
|
|
13
|
+
* run". Comments are stripped by the same reader the source rules use rather than by a second regex,
|
|
14
|
+
* because the hard part is not finding `//` but knowing when it is inside a string.
|
|
15
|
+
* @param text the document to read.
|
|
16
|
+
* @returns the parsed value, or the reason it could not be parsed.
|
|
17
|
+
*/
|
|
18
|
+
export declare const parseJsonc: (text: string) => ParsedJson;
|
|
19
|
+
/**
|
|
20
|
+
* Whether a parsed value can be read as an object with string keys.
|
|
21
|
+
* @param raw the value to narrow, typically a fragment of a parsed manifest.
|
|
22
|
+
* @returns whether it is a non-null object.
|
|
23
|
+
*/
|
|
24
|
+
export declare const isRecord: (raw: unknown) => raw is Record<string, unknown>;
|
|
25
|
+
/**
|
|
26
|
+
* Read a parsed value as an object, or as an empty one when it is not.
|
|
27
|
+
*
|
|
28
|
+
* A malformed value yields no keys rather than an error, so a typo in a manifest leaves a rule reading
|
|
29
|
+
* its defaults instead of failing the whole run. Every default in this package is the strict end of its
|
|
30
|
+
* setting, which is what makes that safe.
|
|
31
|
+
* @param raw the value to read.
|
|
32
|
+
* @returns the value narrowed to an object, or an empty object.
|
|
33
|
+
*/
|
|
34
|
+
export declare const asRecord: (raw: unknown) => Record<string, unknown>;
|
|
35
|
+
/**
|
|
36
|
+
* Read a parsed value as an object of strings, dropping every key whose value is not one.
|
|
37
|
+
* @param raw the value to read.
|
|
38
|
+
* @returns the string-valued keys of the value, or an empty object.
|
|
39
|
+
*/
|
|
40
|
+
export declare const asStringRecord: (raw: unknown) => Record<string, string>;
|
|
41
|
+
/**
|
|
42
|
+
* Whether a parsed value is an array of values still to be narrowed.
|
|
43
|
+
*
|
|
44
|
+
* `Array.isArray` alone narrows an `unknown` to `any[]`, which hands every element back untyped and
|
|
45
|
+
* puts the narrowing beyond the compiler's reach again one step later. This says the same thing and
|
|
46
|
+
* leaves each element `unknown`, so the caller has to state what it expects.
|
|
47
|
+
* @param raw the value to narrow.
|
|
48
|
+
* @returns whether it is an array.
|
|
49
|
+
*/
|
|
50
|
+
export declare const isArray: (raw: unknown) => raw is readonly unknown[];
|
|
51
|
+
/**
|
|
52
|
+
* Read a parsed value as text, or as the empty string when it is not text.
|
|
53
|
+
* @param raw the value to read.
|
|
54
|
+
* @returns the string, or an empty one.
|
|
55
|
+
*/
|
|
56
|
+
export declare const asText: (raw: unknown) => string;
|
|
57
|
+
/**
|
|
58
|
+
* Read a parsed value as text, or as undefined when it is not text.
|
|
59
|
+
*
|
|
60
|
+
* Distinct from `asText` because the two answer different questions. An empty string is a value a rule
|
|
61
|
+
* compares against; `undefined` says the value was never declared, which is how a caller states that a
|
|
62
|
+
* rule has nothing to apply. Collapsing the two would turn "ploaness pins no package manager" into
|
|
63
|
+
* "ploaness requires the package manager to be the empty string".
|
|
64
|
+
* @param raw the value to read.
|
|
65
|
+
* @returns the string, or undefined.
|
|
66
|
+
*/
|
|
67
|
+
export declare const asOptionalText: (raw: unknown) => string | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Read one key of a parsed value.
|
|
70
|
+
* @param raw the value holding the key.
|
|
71
|
+
* @param key the key to read.
|
|
72
|
+
* @returns the value at that key, or undefined when the value is not an object.
|
|
73
|
+
*/
|
|
74
|
+
export declare const readKey: (raw: unknown, key: string) => unknown;
|
|
75
|
+
/**
|
|
76
|
+
* Every package a manifest declares, whichever block it sits in.
|
|
77
|
+
*
|
|
78
|
+
* Three modules asked this question and three of them answered it, which is the shape of a drift rather
|
|
79
|
+
* than of a helper: the CLI's preflight copy read the versions as unknowns and its freshness copy read
|
|
80
|
+
* them as strings, so the two disagreed about what a manifest declaring a non-string version had said.
|
|
81
|
+
* It lives here because the question is about the shape of a parsed manifest and not about any one rule.
|
|
82
|
+
* @param packageJson the parsed manifest.
|
|
83
|
+
* @returns the declared name-to-version pairs, a devDependency winning a name declared in both blocks.
|
|
84
|
+
*/
|
|
85
|
+
export declare const declaredDependencies: (packageJson: unknown) => Record<string, string>;
|
|
86
|
+
//# sourceMappingURL=json-shapes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-shapes.d.ts","sourceRoot":"","sources":["../src/json-shapes.ts"],"names":[],"mappings":"AAYA,+DAA+D;AAC/D,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;CACrC;AAkBD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,UASzC,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,KAAK,OAAO,KAAG,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAC5B,CAAA;AAEzC;;;;;;;;GAQG;AACH,eAAO,MAAM,QAAQ,GAAI,KAAK,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAA+B,CAAA;AAK7F;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CACM,CAAA;AAEzE;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,GAAI,KAAK,OAAO,KAAG,GAAG,IAAI,SAAS,OAAO,EAAwB,CAAA;AAEtF;;;;GAIG;AACH,eAAO,MAAM,MAAM,GAAI,KAAK,OAAO,KAAG,MAA8C,CAAA;AAEpF;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,OAAO,KAAG,MAAM,GAAG,SACZ,CAAA;AAE3C;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAAI,KAAK,OAAO,EAAE,KAAK,MAAM,KAAG,OAA6B,CAAA;AAEjF;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAAI,aAAa,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAY/E,CAAA"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// Narrowing a parsed manifest, which arrives as `unknown` and has to be read as an object.
|
|
2
|
+
//
|
|
3
|
+
// Six modules each carried their own copy of these two functions, and every copy narrowed with a type
|
|
4
|
+
// ASSERTION. That is the wrong instrument twice over: an assertion is a claim the compiler accepts
|
|
5
|
+
// without checking, and `type-coverage --strict` counts each one as untyped, which is what put a 100%
|
|
6
|
+
// score out of reach here. A user-defined type guard says exactly the same thing and IS checked, so the
|
|
7
|
+
// narrowing survives a refactor that changes the shape underneath it.
|
|
8
|
+
//
|
|
9
|
+
// An array narrows to a record, as it did before: `typeof [] === 'object'`, and a manifest key holding
|
|
10
|
+
// an array is read by whichever caller cares, not refused here.
|
|
11
|
+
import { maskLiterals, stripComments } from './source-text.js';
|
|
12
|
+
// A trailing comma is legal in JSONC and in nothing `JSON.parse` accepts, so it is removed after the
|
|
13
|
+
// comments are, when a comma followed only by whitespace and a closing bracket can be recognised.
|
|
14
|
+
const TRAILING_COMMA = /,(?=\s*[\]}])/g;
|
|
15
|
+
// Located on a mask rather than on the document, and removed from the document by offset. Run over the
|
|
16
|
+
// text itself the pattern reads inside a string too, and a glob such as `{ts,}` in a Biome `includes`
|
|
17
|
+
// lost the comma it declared - a silent edit to a parsed value, in the reader every wiring rule uses.
|
|
18
|
+
// Removed from the end backwards so each remaining offset still names the character it named.
|
|
19
|
+
const withoutTrailingCommas = (text) => [...maskLiterals(text).matchAll(TRAILING_COMMA)]
|
|
20
|
+
.map((match) => match.index)
|
|
21
|
+
.reduceRight((current, at) => current.slice(0, at) + current.slice(at + 1), text);
|
|
22
|
+
/**
|
|
23
|
+
* Parse JSON that may carry comments and trailing commas.
|
|
24
|
+
*
|
|
25
|
+
* `tsconfig.json` legally carries both, and so does a Biome config - which meant the rules that judge
|
|
26
|
+
* them threw a SyntaxError out of a pure function on a project scaffolded by `create-payload-app`. The
|
|
27
|
+
* gate that caught it is a precondition, so the whole run halted saying only that the gate "could not
|
|
28
|
+
* run". Comments are stripped by the same reader the source rules use rather than by a second regex,
|
|
29
|
+
* because the hard part is not finding `//` but knowing when it is inside a string.
|
|
30
|
+
* @param text the document to read.
|
|
31
|
+
* @returns the parsed value, or the reason it could not be parsed.
|
|
32
|
+
*/
|
|
33
|
+
export const parseJsonc = (text) => {
|
|
34
|
+
try {
|
|
35
|
+
return {
|
|
36
|
+
value: JSON.parse(withoutTrailingCommas(stripComments(text))),
|
|
37
|
+
problem: undefined,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
return { value: undefined, problem: error instanceof Error ? error.message : String(error) };
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Whether a parsed value can be read as an object with string keys.
|
|
46
|
+
* @param raw the value to narrow, typically a fragment of a parsed manifest.
|
|
47
|
+
* @returns whether it is a non-null object.
|
|
48
|
+
*/
|
|
49
|
+
export const isRecord = (raw) => typeof raw === 'object' && raw !== null;
|
|
50
|
+
/**
|
|
51
|
+
* Read a parsed value as an object, or as an empty one when it is not.
|
|
52
|
+
*
|
|
53
|
+
* A malformed value yields no keys rather than an error, so a typo in a manifest leaves a rule reading
|
|
54
|
+
* its defaults instead of failing the whole run. Every default in this package is the strict end of its
|
|
55
|
+
* setting, which is what makes that safe.
|
|
56
|
+
* @param raw the value to read.
|
|
57
|
+
* @returns the value narrowed to an object, or an empty object.
|
|
58
|
+
*/
|
|
59
|
+
export const asRecord = (raw) => (isRecord(raw) ? raw : {});
|
|
60
|
+
const isStringEntry = (entry) => typeof entry[1] === 'string';
|
|
61
|
+
/**
|
|
62
|
+
* Read a parsed value as an object of strings, dropping every key whose value is not one.
|
|
63
|
+
* @param raw the value to read.
|
|
64
|
+
* @returns the string-valued keys of the value, or an empty object.
|
|
65
|
+
*/
|
|
66
|
+
export const asStringRecord = (raw) => Object.fromEntries(Object.entries(asRecord(raw)).filter(isStringEntry));
|
|
67
|
+
/**
|
|
68
|
+
* Whether a parsed value is an array of values still to be narrowed.
|
|
69
|
+
*
|
|
70
|
+
* `Array.isArray` alone narrows an `unknown` to `any[]`, which hands every element back untyped and
|
|
71
|
+
* puts the narrowing beyond the compiler's reach again one step later. This says the same thing and
|
|
72
|
+
* leaves each element `unknown`, so the caller has to state what it expects.
|
|
73
|
+
* @param raw the value to narrow.
|
|
74
|
+
* @returns whether it is an array.
|
|
75
|
+
*/
|
|
76
|
+
export const isArray = (raw) => Array.isArray(raw);
|
|
77
|
+
/**
|
|
78
|
+
* Read a parsed value as text, or as the empty string when it is not text.
|
|
79
|
+
* @param raw the value to read.
|
|
80
|
+
* @returns the string, or an empty one.
|
|
81
|
+
*/
|
|
82
|
+
export const asText = (raw) => (typeof raw === 'string' ? raw : '');
|
|
83
|
+
/**
|
|
84
|
+
* Read a parsed value as text, or as undefined when it is not text.
|
|
85
|
+
*
|
|
86
|
+
* Distinct from `asText` because the two answer different questions. An empty string is a value a rule
|
|
87
|
+
* compares against; `undefined` says the value was never declared, which is how a caller states that a
|
|
88
|
+
* rule has nothing to apply. Collapsing the two would turn "ploaness pins no package manager" into
|
|
89
|
+
* "ploaness requires the package manager to be the empty string".
|
|
90
|
+
* @param raw the value to read.
|
|
91
|
+
* @returns the string, or undefined.
|
|
92
|
+
*/
|
|
93
|
+
export const asOptionalText = (raw) => typeof raw === 'string' ? raw : undefined;
|
|
94
|
+
/**
|
|
95
|
+
* Read one key of a parsed value.
|
|
96
|
+
* @param raw the value holding the key.
|
|
97
|
+
* @param key the key to read.
|
|
98
|
+
* @returns the value at that key, or undefined when the value is not an object.
|
|
99
|
+
*/
|
|
100
|
+
export const readKey = (raw, key) => asRecord(raw)[key];
|
|
101
|
+
/**
|
|
102
|
+
* Every package a manifest declares, whichever block it sits in.
|
|
103
|
+
*
|
|
104
|
+
* Three modules asked this question and three of them answered it, which is the shape of a drift rather
|
|
105
|
+
* than of a helper: the CLI's preflight copy read the versions as unknowns and its freshness copy read
|
|
106
|
+
* them as strings, so the two disagreed about what a manifest declaring a non-string version had said.
|
|
107
|
+
* It lives here because the question is about the shape of a parsed manifest and not about any one rule.
|
|
108
|
+
* @param packageJson the parsed manifest.
|
|
109
|
+
* @returns the declared name-to-version pairs, a devDependency winning a name declared in both blocks.
|
|
110
|
+
*/
|
|
111
|
+
export const declaredDependencies = (packageJson) => ({
|
|
112
|
+
...asStringRecord(readKey(packageJson, 'dependencies')),
|
|
113
|
+
...asStringRecord(readKey(packageJson, 'devDependencies')),
|
|
114
|
+
// Optional dependencies are INSTALLED dependencies whose absence is tolerated, so every rule about a
|
|
115
|
+
// declared version applies to them: a range still floats, a pin still has to match, and a Payload
|
|
116
|
+
// package still has to agree with its family. Left out, they were the one block a project could put a
|
|
117
|
+
// stale version in and have nothing notice - which is where a real consumer's platform-specific image
|
|
118
|
+
// packages sat, still naming the sharp release the project had just moved off.
|
|
119
|
+
//
|
|
120
|
+
// `peerDependencies` are deliberately NOT here. A peer is a requirement on the consumer's tree rather
|
|
121
|
+
// than a version this package installs, and a range is the correct way to express one.
|
|
122
|
+
...asStringRecord(readKey(packageJson, 'optionalDependencies')),
|
|
123
|
+
});
|
|
124
|
+
//# sourceMappingURL=json-shapes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-shapes.js","sourceRoot":"","sources":["../src/json-shapes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evaluate an SPDX licence expression against the policy.
|
|
3
|
+
*
|
|
4
|
+
* An OR passes when ANY operand does, because the consumer may choose that operand; an AND requires
|
|
5
|
+
* every one; a parenthesised group is evaluated as a unit rather than flattened away.
|
|
6
|
+
* @param expression the declared licence, which may be a compound SPDX expression.
|
|
7
|
+
* @returns whether the policy permits it.
|
|
8
|
+
*/
|
|
9
|
+
export declare const isLicenseAllowed: (expression: string) => boolean;
|
|
10
|
+
export interface LicensedPackage {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly license: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const findLicenseViolations: (packages: readonly LicensedPackage[]) => readonly LicensedPackage[];
|
|
15
|
+
//# sourceMappingURL=license-allowlist.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"license-allowlist.d.ts","sourceRoot":"","sources":["../src/license-allowlist.ts"],"names":[],"mappings":"AAsKA;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAAI,YAAY,MAAM,KAAG,OAWrD,CAAA;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAGD,eAAO,MAAM,qBAAqB,GAChC,UAAU,SAAS,eAAe,EAAE,KACnC,SAAS,eAAe,EACmE,CAAA"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { escapeForRegex } from './text-escapes.js';
|
|
2
|
+
// License allowlist policy for dependencies. The pure logic - the allowlist and the SPDX-expression
|
|
3
|
+
// evaluator - lives here so it is unit-tested; the `licenses` gate in
|
|
4
|
+
// packages/cli/src/checks/dependencies.ts shells out to pnpm and reports.
|
|
5
|
+
// The two groups are arrays rather than sets so the allowlist can be assembled with a single
|
|
6
|
+
// constructor call. Merging two sets would want `Set.prototype.union`, which the ES2023 lib target does
|
|
7
|
+
// not carry, and a lint fix that reaches for it produces code that does not compile.
|
|
8
|
+
// Permissive licenses: no copyleft obligations, safe for an MIT-licensed template.
|
|
9
|
+
// Three entries are here for a reason the identifier does not show. `PSF-2.0` and `Python-2.0` are the
|
|
10
|
+
// same terms under two names, which is not a distinction a consumer can act on: `argparse` - reached
|
|
11
|
+
// through `js-yaml`, so present in almost every tree rather than chosen - shipped 3.0.0 as the second
|
|
12
|
+
// and 3.0.1 as the first. `EDL-1.0` carries the Eclipse name but is the BSD-3-Clause text, so it
|
|
13
|
+
// belongs beside BSD rather than beside EPL. `X11` is a separate SPDX id from `MIT` for the same
|
|
14
|
+
// terms, and a package that picks it is not asking for anything MIT does not already grant.
|
|
15
|
+
const PERMISSIVE = [
|
|
16
|
+
'0BSD',
|
|
17
|
+
'AFL-2.1',
|
|
18
|
+
'AFL-3.0',
|
|
19
|
+
'Apache-2.0',
|
|
20
|
+
'Artistic-2.0',
|
|
21
|
+
'BSD-2-Clause',
|
|
22
|
+
'BSD-3-Clause',
|
|
23
|
+
'BSL-1.0',
|
|
24
|
+
'BlueOak-1.0.0',
|
|
25
|
+
'CC-BY-3.0',
|
|
26
|
+
'CC-BY-4.0',
|
|
27
|
+
'CC0-1.0',
|
|
28
|
+
'EDL-1.0',
|
|
29
|
+
'ISC',
|
|
30
|
+
'MIT',
|
|
31
|
+
'MIT-0',
|
|
32
|
+
'MulanPSL-2.0',
|
|
33
|
+
'NCSA',
|
|
34
|
+
'OFL-1.1',
|
|
35
|
+
'PSF-2.0',
|
|
36
|
+
'PostgreSQL',
|
|
37
|
+
'Python-2.0',
|
|
38
|
+
'UPL-1.0',
|
|
39
|
+
'Unicode-3.0',
|
|
40
|
+
'Unicode-DFS-2016',
|
|
41
|
+
'Unlicense',
|
|
42
|
+
'W3C',
|
|
43
|
+
'WTFPL',
|
|
44
|
+
'X11',
|
|
45
|
+
'Zlib',
|
|
46
|
+
];
|
|
47
|
+
// Weak copyleft, permitted only as UNMODIFIED dependencies: the file-level (MPL, EPL, CDDL) and
|
|
48
|
+
// dynamic-linking (LGPL) copyleft does not reach this project's own source. Each id is listed
|
|
49
|
+
// explicitly so it stays a conscious decision. Strong copyleft (GPL, AGPL) is deliberately absent and
|
|
50
|
+
// therefore rejected, and so is a license that restricts the field of use - `Hippocratic-2.1` reads as
|
|
51
|
+
// an ethical licence and is not an open-source one, which is a distinction only this list records.
|
|
52
|
+
//
|
|
53
|
+
// The bare `LGPL-2.1` and `LGPL-3.0` are DEPRECATED SPDX ids, and they are here because a policy
|
|
54
|
+
// admits a license rather than a spelling of one: listing `-only` and `-or-later` while omitting the
|
|
55
|
+
// form most packages actually write rejected the licence this list was written to permit. The `+`
|
|
56
|
+
// suffix reaches the bare id too, so `LGPL-3.0+` resolves here rather than nowhere.
|
|
57
|
+
const WEAK_COPYLEFT = [
|
|
58
|
+
'CDDL-1.0',
|
|
59
|
+
'CDDL-1.1',
|
|
60
|
+
'EPL-1.0',
|
|
61
|
+
'EPL-2.0',
|
|
62
|
+
'LGPL-2.1',
|
|
63
|
+
'LGPL-2.1-only',
|
|
64
|
+
'LGPL-2.1-or-later',
|
|
65
|
+
'LGPL-3.0',
|
|
66
|
+
'LGPL-3.0-only',
|
|
67
|
+
'LGPL-3.0-or-later',
|
|
68
|
+
'MPL-1.1',
|
|
69
|
+
'MPL-2.0',
|
|
70
|
+
];
|
|
71
|
+
const ALLOWED = new Set([...PERMISSIVE, ...WEAK_COPYLEFT]);
|
|
72
|
+
// SPDX ids are case-insensitive in the registries that emit them, and `Apache-2.0` arrives spelled at
|
|
73
|
+
// least three ways. The allowlist is matched on a folded id so a casing difference is not a licence
|
|
74
|
+
// decision. A `WITH` exception (`GPL-2.0 WITH Classpath-exception-2.0`) names the same licence plus a
|
|
75
|
+
// grant, so the licence half decides; a `+` suffix means "or later", which is the same licence too.
|
|
76
|
+
const ALLOWED_FOLDED = new Set([...ALLOWED].map((id) => id.toLowerCase()));
|
|
77
|
+
// Anchored on a single space run rather than a nested quantifier: `\s+WITH\s+(?:\S.*)?$` backtracks
|
|
78
|
+
// super-linearly on a long id, and an expression comes from a registry rather than from this repository.
|
|
79
|
+
const WITH_EXCEPTION = /\sWITH\s[\s\S]*$/i;
|
|
80
|
+
const OR_LATER = /\+$/;
|
|
81
|
+
const isAllowedId = (id) => ALLOWED_FOLDED.has(id.trim().replace(WITH_EXCEPTION, '').replace(OR_LATER, '').toLowerCase());
|
|
82
|
+
// The operators, lowest precedence first. SPDX binds AND more tightly than OR, so a correct evaluator
|
|
83
|
+
// splits on OR before AND - and the ONLY correct order is that one. Splitting on AND first, after
|
|
84
|
+
// stripping the parentheses, turned `(MIT OR Apache-2.0) AND ISC` into the operands
|
|
85
|
+
// `MIT OR Apache-2.0` and `ISC`, and then failed the first as though it were an unknown id: every
|
|
86
|
+
// mixed expression was reported as a licence violation whatever it actually said.
|
|
87
|
+
const OR = ' OR ';
|
|
88
|
+
const AND = ' AND ';
|
|
89
|
+
const stepDepth = (depth, character) => {
|
|
90
|
+
if (character === '(') {
|
|
91
|
+
return depth + 1;
|
|
92
|
+
}
|
|
93
|
+
return character === ')' ? depth - 1 : depth;
|
|
94
|
+
};
|
|
95
|
+
// Both figures come from one walk, because the two questions below are about the same characters: how
|
|
96
|
+
// far a fragment leaves the parentheses open, and whether it ever closed a group it had not opened.
|
|
97
|
+
const walkParentheses = (text) =>
|
|
98
|
+
// Only the two parentheses are counted, and neither of them decomposes.
|
|
99
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-spread -- see the note above
|
|
100
|
+
[...text].reduce((state, character) => {
|
|
101
|
+
const depth = stepDepth(state.depth, character);
|
|
102
|
+
return { depth, lowest: Math.min(state.lowest, depth) };
|
|
103
|
+
}, { depth: 0, lowest: 0 });
|
|
104
|
+
// How far a fragment leaves the parentheses open, so an operator inside a group is not split on.
|
|
105
|
+
const balanceOf = (text) => walkParentheses(text).depth;
|
|
106
|
+
// Where the operator occurs at parenthesis depth zero, which is the only place it separates operands.
|
|
107
|
+
// An occurrence inside a group belongs to that group: in `(MIT OR Apache-2.0) AND ISC` the OR is the
|
|
108
|
+
// group's own, and splitting on it would produce operands the author never wrote.
|
|
109
|
+
const splitPoints = (expression, operator) => [...expression.matchAll(new RegExp(escapeForRegex(operator), 'g'))]
|
|
110
|
+
.map((match) => match.index)
|
|
111
|
+
.filter((index) => balanceOf(expression.slice(0, index)) === 0);
|
|
112
|
+
const splitOutside = (expression, operator) => {
|
|
113
|
+
const points = splitPoints(expression, operator);
|
|
114
|
+
const ends = [...points, expression.length];
|
|
115
|
+
return [0, ...points.map((point) => point + operator.length)].map((start, index) => expression.slice(start, ends[index] ?? expression.length));
|
|
116
|
+
};
|
|
117
|
+
// Whether the outer parentheses enclose the WHOLE expression, rather than opening one group and closing
|
|
118
|
+
// a different one. A net balance of zero does not answer that, and answering it that way was wrong in
|
|
119
|
+
// both directions: `(MIT) OR (ISC)` also nets to zero, and stripping its outer characters left
|
|
120
|
+
// `MIT) OR (ISC`, where the early `)` drives the running depth negative so no operator sits at depth
|
|
121
|
+
// zero any more. Such an expression was then read as one unrecognised id and rejected - while
|
|
122
|
+
// `(MIT OR GPL-3.0-only) AND (GPL-3.0-only OR AGPL-3.0-only)` split at two ORs that were never
|
|
123
|
+
// top-level, found `MIT` among the pieces, and passed. The lowest depth the inner text reaches is what
|
|
124
|
+
// separates the two cases.
|
|
125
|
+
const isWhollyEnclosed = (inner) => {
|
|
126
|
+
const walk = walkParentheses(inner);
|
|
127
|
+
return walk.depth === 0 && walk.lowest === 0;
|
|
128
|
+
};
|
|
129
|
+
const unwrap = (expression) => {
|
|
130
|
+
const trimmed = expression.trim();
|
|
131
|
+
return trimmed.startsWith('(') && trimmed.endsWith(')') && isWhollyEnclosed(trimmed.slice(1, -1))
|
|
132
|
+
? unwrap(trimmed.slice(1, -1))
|
|
133
|
+
: trimmed;
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Evaluate an SPDX licence expression against the policy.
|
|
137
|
+
*
|
|
138
|
+
* An OR passes when ANY operand does, because the consumer may choose that operand; an AND requires
|
|
139
|
+
* every one; a parenthesised group is evaluated as a unit rather than flattened away.
|
|
140
|
+
* @param expression the declared licence, which may be a compound SPDX expression.
|
|
141
|
+
* @returns whether the policy permits it.
|
|
142
|
+
*/
|
|
143
|
+
export const isLicenseAllowed = (expression) => {
|
|
144
|
+
const clean = unwrap(expression);
|
|
145
|
+
const alternatives = splitOutside(clean, OR);
|
|
146
|
+
if (alternatives.length > 1) {
|
|
147
|
+
return alternatives.some((part) => isLicenseAllowed(part));
|
|
148
|
+
}
|
|
149
|
+
const conjuncts = splitOutside(clean, AND);
|
|
150
|
+
if (conjuncts.length > 1) {
|
|
151
|
+
return conjuncts.every((part) => isLicenseAllowed(part));
|
|
152
|
+
}
|
|
153
|
+
return isAllowedId(clean);
|
|
154
|
+
};
|
|
155
|
+
// Return the packages whose license is not permitted by policy; an empty array means a clean tree.
|
|
156
|
+
export const findLicenseViolations = (packages) => packages.filter((package_) => !isLicenseAllowed(package_.license));
|
|
157
|
+
//# sourceMappingURL=license-allowlist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"license-allowlist.js","sourceRoot":"","sources":["../src/license-allowlist.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** The sentence of the governing standard this module decides, quoted back in every refusal. */
|
|
2
|
+
export declare const NETWORK_RULE: string;
|
|
3
|
+
/** Which runtime entry point asked. Each reaches its verdict differently, so it is data, not a flag. */
|
|
4
|
+
export type NetworkApi = 'connect' | 'lookup' | 'resolve' | 'fetch';
|
|
5
|
+
/** One attempted reach, normalised from whichever entry point a test called. */
|
|
6
|
+
export interface NetworkAttempt {
|
|
7
|
+
readonly api: NetworkApi;
|
|
8
|
+
/** The host as the caller wrote it, or undefined for a unix socket, which is not a network at all. */
|
|
9
|
+
readonly host: string | undefined;
|
|
10
|
+
/** What a refusal names, for example `127.0.0.1:5432` or `https://api.example.com/v1`. */
|
|
11
|
+
readonly destination: string;
|
|
12
|
+
}
|
|
13
|
+
/** One entry of `os.networkInterfaces()`, narrowed to the single field this module reads. */
|
|
14
|
+
export interface NetworkInterfaceAddress {
|
|
15
|
+
readonly address: string;
|
|
16
|
+
}
|
|
17
|
+
/** The resolver entry points, every one of which queries a nameserver rather than reading a hosts file. */
|
|
18
|
+
export declare const RESOLVER_METHODS: readonly string[];
|
|
19
|
+
/**
|
|
20
|
+
* The addresses that name this machine, read out of an `os.networkInterfaces()` result.
|
|
21
|
+
*
|
|
22
|
+
* A test that connects to the box's own routable address is still on the machine it runs on, so those
|
|
23
|
+
* addresses join the loopback range rather than being refused with everything else.
|
|
24
|
+
* @param interfaces the interface map, as `os.networkInterfaces()` returns it.
|
|
25
|
+
* @returns every address it carries, in the canonical spelling {@link isMachineLocalHost} compares against.
|
|
26
|
+
*/
|
|
27
|
+
export declare const localAddresses: (interfaces: Readonly<Record<string, readonly NetworkInterfaceAddress[] | undefined>>) => ReadonlySet<string>;
|
|
28
|
+
/**
|
|
29
|
+
* Whether a host names the machine the test runs on.
|
|
30
|
+
*
|
|
31
|
+
* A name that is not one of the localhost spellings is refused on its face rather than resolved, because
|
|
32
|
+
* a resolution is itself the thing being refused. That is why a bare service name such as `postgres`,
|
|
33
|
+
* and a docker gateway such as `host.docker.internal`, do not pass: neither can be shown to be this
|
|
34
|
+
* machine without asking a nameserver.
|
|
35
|
+
* @param host the host as the caller wrote it, or undefined when the caller named none.
|
|
36
|
+
* @param local the addresses this machine carries, from {@link localAddresses}.
|
|
37
|
+
* @returns true when the reach stays on this machine.
|
|
38
|
+
*/
|
|
39
|
+
export declare const isMachineLocalHost: (host: string | undefined, local: ReadonlySet<string>) => boolean;
|
|
40
|
+
/**
|
|
41
|
+
* The host a URL names.
|
|
42
|
+
*
|
|
43
|
+
* Undefined when the value names no host - a relative path, which under a DOM environment is the page's
|
|
44
|
+
* own origin and reaches nothing, or a string that is not a URL at all.
|
|
45
|
+
* @param rawUrl the value a test passed to fetch.
|
|
46
|
+
* @returns the host, or undefined.
|
|
47
|
+
*/
|
|
48
|
+
export declare const hostOfUrl: (rawUrl: string) => string | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Read one `net.Socket.prototype.connect` call, whichever of its three forms the caller used.
|
|
51
|
+
*
|
|
52
|
+
* A unix socket reports no host, because a path is not a network: the two ends are the same machine by
|
|
53
|
+
* construction, and refusing one would break every test that talks to a local service over a socket file.
|
|
54
|
+
* @param callArguments the arguments the call was made with.
|
|
55
|
+
* @returns the attempt, normalised.
|
|
56
|
+
*/
|
|
57
|
+
export declare const describeSocketTarget: (callArguments: readonly unknown[]) => NetworkAttempt;
|
|
58
|
+
/**
|
|
59
|
+
* Decide one attempted reach.
|
|
60
|
+
*
|
|
61
|
+
* A resolver query is refused whatever host it names, loopback included. The resolver family bypasses
|
|
62
|
+
* the hosts file and sends a packet to a nameserver, so `resolve4('localhost')` leaves the machine as
|
|
63
|
+
* surely as any other name does.
|
|
64
|
+
* @param attempt the reach to judge.
|
|
65
|
+
* @param local the addresses this machine carries, from {@link localAddresses}.
|
|
66
|
+
* @returns undefined when the reach is allowed, or the message a refusal should carry.
|
|
67
|
+
*/
|
|
68
|
+
export declare const findNetworkEscape: (attempt: NetworkAttempt, local: ReadonlySet<string>) => string | undefined;
|
|
69
|
+
//# sourceMappingURL=network-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-policy.d.ts","sourceRoot":"","sources":["../src/network-policy.ts"],"names":[],"mappings":"AAcA,gGAAgG;AAChG,eAAO,MAAM,YAAY,EAAE,MAAmE,CAAA;AAE9F,wGAAwG;AACxG,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAA;AAEnE,gFAAgF;AAChF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAA;IACxB,sGAAsG;IACtG,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,0FAA0F;IAC1F,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED,6FAA6F;AAC7F,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,2GAA2G;AAC3G,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAe7C,CAAA;AA6CD;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GACzB,YAAY,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,uBAAuB,EAAE,GAAG,SAAS,CAAC,CAAC,KACnF,WAAW,CAAC,MAAM,CASlB,CAAA;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,GAC7B,MAAM,MAAM,GAAG,SAAS,EACxB,OAAO,WAAW,CAAC,MAAM,CAAC,KACzB,OAMF,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,KAAG,MAAM,GAAG,SAMnD,CAAA;AAuBD;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAAI,eAAe,SAAS,OAAO,EAAE,KAAG,cAcxE,CAAA;AAUD;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,GAC5B,SAAS,cAAc,EACvB,OAAO,WAAW,CAAC,MAAM,CAAC,KACzB,MAAM,GAAG,SAKX,CAAA"}
|