@brydio/manifest 0.1.0-alpha.5 → 0.1.0-alpha.50
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 +1 -1
- package/package.json +2 -2
- package/src/anonymous.d.ts +42 -0
- package/src/anonymous.js +86 -0
- package/src/base.d.ts +17 -1
- package/src/base.js +13 -1
- package/src/bundle.d.ts +8 -1
- package/src/bundle.js +28 -3
- package/src/confirm-email.d.ts +40 -0
- package/src/confirm-email.js +78 -0
- package/src/define.d.ts +1 -1
- package/src/define.js +1 -1
- package/src/field-types.d.ts +40 -4
- package/src/field-types.js +59 -9
- package/src/grants.d.ts +12 -2
- package/src/grants.js +28 -2
- package/src/index.d.ts +10 -5
- package/src/index.js +10 -5
- package/src/migrations.d.ts +1 -1
- package/src/migrations.js +29 -0
- package/src/open-schema.d.ts +128 -0
- package/src/open-schema.js +444 -0
- package/src/readers.d.ts +54 -0
- package/src/readers.js +96 -0
- package/src/requirements.d.ts +122 -0
- package/src/requirements.js +692 -0
- package/src/schema.d.ts +539 -8
- package/src/schema.js +440 -27
- package/src/secrets.d.ts +14 -0
- package/src/secrets.js +38 -5
- package/src/validate.d.ts +8 -2
- package/src/validate.js +7 -5
package/src/secrets.js
CHANGED
|
@@ -35,21 +35,21 @@ const isRealValue = (value) => {
|
|
|
35
35
|
return false;
|
|
36
36
|
return true;
|
|
37
37
|
};
|
|
38
|
-
function walk(node, at, found) {
|
|
38
|
+
function walk(node, at, found, publicValue = () => false) {
|
|
39
39
|
if (Array.isArray(node)) {
|
|
40
|
-
node.forEach((one, index) => walk(one, `${at}[${index}]`, found));
|
|
40
|
+
node.forEach((one, index) => walk(one, `${at}[${index}]`, found, publicValue));
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
if (!node || typeof node !== 'object')
|
|
44
44
|
return;
|
|
45
45
|
for (const [key, value] of Object.entries(node)) {
|
|
46
46
|
const path = at ? `${at}.${key}` : key;
|
|
47
|
-
if (VALUE_KEYS.has(key) && isRealValue(value)) {
|
|
47
|
+
if (VALUE_KEYS.has(key) && isRealValue(value) && !publicValue(path)) {
|
|
48
48
|
// Never quoted back: a report that repeated the secret would copy it somewhere else.
|
|
49
49
|
found.push({ code: 'secret_in_bundle', message: SECRET_MESSAGE, path });
|
|
50
50
|
continue;
|
|
51
51
|
}
|
|
52
|
-
walk(value, path, found);
|
|
52
|
+
walk(value, path, found, publicValue);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
@@ -59,9 +59,20 @@ function walk(node, at, found) {
|
|
|
59
59
|
*/
|
|
60
60
|
export function secretsInJson(document, at) {
|
|
61
61
|
const found = [];
|
|
62
|
-
walk(document, at, found);
|
|
62
|
+
walk(document, at, found, path => DECLARATIONS.some(declared => declared.test(path)));
|
|
63
63
|
return found;
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Names in an app.json that read like credentials but are declarations: a
|
|
67
|
+
* placement's identity, a collection's field definition (an open-schema
|
|
68
|
+
* companion must declare `key`), and a tool's input field. Their values are
|
|
69
|
+
* types and names, never secrets.
|
|
70
|
+
*/
|
|
71
|
+
const DECLARATIONS = [
|
|
72
|
+
/(?:^|\.)placements\[\d+\]\.key$/,
|
|
73
|
+
/(?:^|\.)data\.[^.[\]]+\.schema\.[^.[\]]+$/,
|
|
74
|
+
/(?:^|\.)tools\.custom\[\d+\]\.input\.[^.[\]]+$/,
|
|
75
|
+
];
|
|
65
76
|
/** Every secret declared in a bundle's files, as the server finds them. */
|
|
66
77
|
export function findSecrets(files, root = '') {
|
|
67
78
|
const found = [];
|
|
@@ -79,3 +90,25 @@ export function findSecrets(files, root = '') {
|
|
|
79
90
|
}
|
|
80
91
|
return found;
|
|
81
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* The server's sentence for `developer_key_in_bundle` (ADR-A22), word for
|
|
95
|
+
* word: `DEVELOPER_KEY_IN_BUNDLE` in Brydio's `app-publish.service.ts`.
|
|
96
|
+
*/
|
|
97
|
+
export const DEVELOPER_KEY_MESSAGE = 'That package contains a Brydio developer API key. A key belongs on your own server, never in an app: revoke it in Settings › Developer, and call Brydio’s model from a handler with the model grant instead.';
|
|
98
|
+
/** A developer API key's exact shape, anywhere in a text. */
|
|
99
|
+
const DEVELOPER_KEY = /bry_live_[0-9a-f]{12}_[A-Za-z0-9_-]{43}/;
|
|
100
|
+
/** Whether a text holds a Brydio developer API key. */
|
|
101
|
+
export const holdsDeveloperKey = (text) => DEVELOPER_KEY.test(text);
|
|
102
|
+
/**
|
|
103
|
+
* The first file holding a developer API key, by path, as Brydio's publish
|
|
104
|
+
* route finds it (`developerKeyIn`). Unlike the declaration scan, every file
|
|
105
|
+
* is read, scripts included: the key's shape is exact enough that a match is
|
|
106
|
+
* a key, not a guess, and no part of an app may hold one (ADR-A24).
|
|
107
|
+
*/
|
|
108
|
+
export function developerKeyIn(files) {
|
|
109
|
+
for (const [path, bytes] of files) {
|
|
110
|
+
if (holdsDeveloperKey(new TextDecoder('latin1').decode(bytes)))
|
|
111
|
+
return path;
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
package/src/validate.d.ts
CHANGED
|
@@ -22,6 +22,12 @@ export interface ManifestValidation {
|
|
|
22
22
|
manifest?: AppManifestWithData;
|
|
23
23
|
problems: ManifestProblem[];
|
|
24
24
|
}
|
|
25
|
-
export declare function validateManifest(source: unknown
|
|
25
|
+
export declare function validateManifest(source: unknown,
|
|
26
|
+
/** `retired`: a manifest being written now, which may not use a retired kind such as `project-tab`. */
|
|
27
|
+
options?: {
|
|
28
|
+
retired?: boolean;
|
|
29
|
+
}): ManifestValidation;
|
|
26
30
|
/** Parses the text of `.brydio/app.json` and validates it. */
|
|
27
|
-
export declare function validateManifestText(text: string
|
|
31
|
+
export declare function validateManifestText(text: string, options?: {
|
|
32
|
+
retired?: boolean;
|
|
33
|
+
}): ManifestValidation;
|
package/src/validate.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { appManifestSchema } from "./schema.js";
|
|
2
|
-
export function validateManifest(source
|
|
3
|
-
|
|
1
|
+
import { appManifestSchema, newAppManifestSchema } from "./schema.js";
|
|
2
|
+
export function validateManifest(source,
|
|
3
|
+
/** `retired`: a manifest being written now, which may not use a retired kind such as `project-tab`. */
|
|
4
|
+
options = {}) {
|
|
5
|
+
const parsed = (options.retired ? newAppManifestSchema : appManifestSchema).safeParse(source);
|
|
4
6
|
if (parsed.success)
|
|
5
7
|
return { ok: true, manifest: parsed.data, problems: [] };
|
|
6
8
|
return {
|
|
@@ -14,7 +16,7 @@ export function validateManifest(source) {
|
|
|
14
16
|
};
|
|
15
17
|
}
|
|
16
18
|
/** Parses the text of `.brydio/app.json` and validates it. */
|
|
17
|
-
export function validateManifestText(text) {
|
|
19
|
+
export function validateManifestText(text, options = {}) {
|
|
18
20
|
let json;
|
|
19
21
|
try {
|
|
20
22
|
json = JSON.parse(text);
|
|
@@ -25,5 +27,5 @@ export function validateManifestText(text) {
|
|
|
25
27
|
problems: [{ code: 'manifest_not_json', message: `The manifest is not valid JSON: ${error instanceof Error ? error.message : String(error)}` }],
|
|
26
28
|
};
|
|
27
29
|
}
|
|
28
|
-
return validateManifest(json);
|
|
30
|
+
return validateManifest(json, options);
|
|
29
31
|
}
|