@runeditrun/rer 0.2.0 → 0.2.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 -4
- package/cli/README.md +4 -2
- package/cli/auth-copy.mjs +25 -18
- package/cli/bounded.mjs +13 -4
- package/cli/contract.mjs +3 -3
- package/cli/deploy-inputs.mjs +33 -0
- package/cli/deploy-owner.mjs +61 -0
- package/cli/deploy.mjs +95 -9
- package/cli/detached-server.mjs +51 -0
- package/cli/door.mjs +1 -1
- package/cli/hosted-output.mjs +2 -2
- package/cli/hydration/check.mjs +2 -2
- package/cli/inspect.mjs +24 -32
- package/cli/lifecycle.mjs +14 -4
- package/cli/main.mjs +1 -0
- package/cli/managed-server.mjs +12 -5
- package/cli/parse.mjs +5 -2
- package/cli/pnpm-probe.mjs +14 -0
- package/cli/pnpm-runtime.mjs +22 -22
- package/cli/portability-policy.mjs +55 -0
- package/cli/portability-worker.mjs +8 -4
- package/cli/portability.mjs +20 -4
- package/cli/project-pnpm.mjs +67 -0
- package/cli/release.mjs +36 -0
- package/cli/server-registry.mjs +2 -2
- package/cli/site-bindings.mjs +291 -0
- package/cli/site-browser-objects.mjs +36 -0
- package/cli/site-check.mjs +55 -31
- package/cli/site-client.mjs +50 -0
- package/cli/site-data.mjs +55 -0
- package/cli/site-entities.json +1 -0
- package/cli/site-input-assets.mjs +58 -0
- package/cli/site-inputs.mjs +79 -0
- package/cli/site-markup.mjs +102 -0
- package/cli/site-private.mjs +36 -0
- package/cli/site-references.mjs +243 -0
- package/cli/site-render.mjs +7 -5
- package/cli/site-syntax.mjs +21 -0
- package/cli/site.mjs +32 -11
- package/global/CHANGELOG.md +39 -0
- package/global/README.md +15 -4
- package/global/cli/install.mjs +26 -9
- package/global/cli/path-link.mjs +30 -0
- package/global/cli/status.mjs +1 -1
- package/global/cli/uninstall.mjs +5 -1
- package/global/launch/install-pinned.mjs +4 -0
- package/global/main.mjs +30 -3
- package/global/output.mjs +12 -0
- package/global/registry.mjs +2 -2
- package/global/rer.mjs +3 -0
- package/modules/container/deploy-input.mjs +5 -9
- package/modules/dependencies/auth.mjs +2 -1
- package/modules/deploy-kit/README.md +25 -7
- package/modules/deploy-kit/d1-import.mjs +35 -0
- package/modules/deploy-kit/deploy.mjs +9 -5
- package/modules/deploy-kit/diagnostics.mjs +65 -0
- package/modules/deploy-kit/env-file.mjs +26 -0
- package/modules/deploy-kit/health-request.mjs +6 -1
- package/modules/deploy-kit/health.mjs +35 -15
- package/modules/deploy-kit/migration-ledger.mjs +48 -0
- package/modules/deploy-kit/migrations.mjs +11 -15
- package/modules/deploy-kit/owner-cli.mjs +29 -10
- package/modules/deploy-kit/owner-remove.mjs +105 -0
- package/modules/deploy-kit/owner-secret.mjs +49 -0
- package/modules/deploy-kit/owner.mjs +71 -10
- package/modules/deploy-kit/provider.mjs +59 -7
- package/modules/job-queue/config.mjs +4 -2
- package/modules/operator-auth/accounts/native.mjs +1 -1
- package/modules/operator-auth/dev/badge.mjs +4 -1
- package/modules/operator-auth/identity/oidc/README.md +18 -0
- package/modules/operator-auth/identity/oidc/config.mjs +4 -2
- package/modules/operator-auth/identity/oidc/index.d.mts +1 -1
- package/modules/operator-auth/identity/oidc/index.mjs +28 -9
- package/modules/operator-auth/identity/oidc/network.mjs +9 -4
- package/modules/operator-auth/identity/oidc/store.mjs +19 -3
- package/modules/operator-auth/index.d.mts +6 -9
- package/modules/operator-auth/page.mjs +1 -1
- package/modules/operator-auth/routes.mjs +1 -1
- package/modules/operator-auth/service.mjs +1 -0
- package/modules/operator-auth/signin/index.d.mts +11 -0
- package/modules/operator-auth/signin/index.mjs +10 -7
- package/modules/portability/README.md +28 -0
- package/modules/portability/bridge.mjs +10 -3
- package/modules/portability/import.mjs +4 -2
- package/modules/release/README.md +63 -0
- package/modules/release/keygen.mjs +18 -0
- package/modules/release/produce.mjs +9 -0
- package/modules/release/sign.mjs +44 -0
- package/modules/release/signature.mjs +336 -0
- package/modules/release/signing-cli.mjs +56 -0
- package/modules/release/signing-io.mjs +61 -0
- package/modules/release/signing-key.mjs +22 -0
- package/modules/release/statement.mjs +80 -0
- package/modules/release/vectors/generate.mjs +381 -0
- package/modules/release/vectors/release-signature-vectors.json +2305 -0
- package/modules/release/verify.mjs +27 -0
- package/onboarding/commands.mjs +3 -1
- package/onboarding/production-assets.mjs +23 -0
- package/onboarding/production-runtime.mjs +8 -4
- package/package.json +2 -1
- package/scripts/publish-check/README.md +27 -17
- package/scripts/publish-check/content_identities.py +14 -233
- package/scripts/publish-check/git_history.py +2 -2
- package/scripts/publish-check/gitleaks.toml +1 -1
- package/scripts/publish-check/history_scan.py +6 -4
- package/scripts/publish-check/hygiene_config.py +3 -1
- package/scripts/publish-check/public_hygiene.py +29 -5
- package/scripts/publish-check/publication-config.json +9 -1
- package/scripts/publish-check/source_metadata.py +62 -0
- package/scripts/publish-check/source_shapes.py +91 -0
- package/scripts/publish-check/tree_scan.py +2 -2
- package/scripts/publish-check/source_hashes.mjs +0 -6
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Digest fields in the formats emitted by edition-authoring cli/sources.mjs.
|
|
2
|
+
|
|
3
|
+
This recognizes metadata, not its freshness or integrity. Authoring's check
|
|
4
|
+
owns those validations; a retained, unselected archive is still metadata.
|
|
5
|
+
Only enumerated JSON value locations qualify, never arbitrary nested names.
|
|
6
|
+
"""
|
|
7
|
+
import re
|
|
8
|
+
from json_identity import HEX, GIT_REVISION
|
|
9
|
+
import source_shapes
|
|
10
|
+
|
|
11
|
+
ARCHIVE = re.compile(r'\.edition/sources/([a-f0-9]{64})\.json\Z')
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def fields(value, pointer, names, pattern=HEX):
|
|
15
|
+
if isinstance(value, dict):
|
|
16
|
+
for name in names:
|
|
17
|
+
if isinstance(value.get(name), str) and pattern.fullmatch(value[name]):
|
|
18
|
+
yield (*pointer, name)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def pin(value, pointer):
|
|
22
|
+
# sources.mjs and cli.mjs emit this same three-digest reference shape.
|
|
23
|
+
if source_shapes.pin(value):
|
|
24
|
+
yield from fields(value, pointer, ('key', 'digest', 'sha256'))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def origin(value, pointer):
|
|
28
|
+
# snapshotOrigin in projection-lock.mjs copies one immutable identity.
|
|
29
|
+
if not source_shapes.reference(value):
|
|
30
|
+
return
|
|
31
|
+
if 'projection' not in value:
|
|
32
|
+
yield from fields(value, pointer, ('revision',), GIT_REVISION)
|
|
33
|
+
else:
|
|
34
|
+
yield from fields(value['projection'], (*pointer, 'projection'), ('originalSha256', 'recipeSha256'))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def source_pointers(path, value):
|
|
38
|
+
if not isinstance(value, dict):
|
|
39
|
+
return
|
|
40
|
+
if path == 'sources.lock.json':
|
|
41
|
+
if not source_shapes.lock(value):
|
|
42
|
+
return
|
|
43
|
+
yield from fields(value, (), ('manifest',))
|
|
44
|
+
yield from fields(value['toolchain'], ('toolchain',), ('sha256',))
|
|
45
|
+
yield from pin(value.get('parent'), ('parent',))
|
|
46
|
+
for index, component in enumerate(value['components']):
|
|
47
|
+
pointer = ('components', index)
|
|
48
|
+
yield from pin(component.get('baseline'), (*pointer, 'baseline'))
|
|
49
|
+
source = component['source']
|
|
50
|
+
if source['kind'] == 'git':
|
|
51
|
+
yield from origin(source, (*pointer, 'source'))
|
|
52
|
+
else:
|
|
53
|
+
yield from origin(source.get('origin'), (*pointer, 'source', 'origin'))
|
|
54
|
+
for name, entry in value['files'].items():
|
|
55
|
+
yield from fields(entry, ('files', name), ('sha256',))
|
|
56
|
+
elif ARCHIVE.fullmatch(path):
|
|
57
|
+
if not source_shapes.archive(value):
|
|
58
|
+
return
|
|
59
|
+
yield from fields(value, (), ('key', 'digest'))
|
|
60
|
+
yield from origin(value['origin'], ('origin',))
|
|
61
|
+
for index, dependency in enumerate(value.get('dependencies', [])):
|
|
62
|
+
yield from pin(dependency, ('dependencies', index))
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Local record shapes emitted by edition-authoring, without integrity checks."""
|
|
2
|
+
import re
|
|
3
|
+
from copy_identities import relative_path
|
|
4
|
+
from json_identity import HEX, GIT_REVISION
|
|
5
|
+
|
|
6
|
+
IDENTITY = re.compile(r'[a-zA-Z0-9][a-zA-Z0-9._-]*/[a-zA-Z0-9][a-zA-Z0-9._-]*\Z')
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def matches(value, pattern=HEX):
|
|
10
|
+
return isinstance(value, str) and bool(pattern.fullmatch(value))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def pin(value):
|
|
14
|
+
return isinstance(value, dict) and all(matches(value.get(k)) for k in ('key', 'digest', 'sha256'))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def paths(value):
|
|
18
|
+
return isinstance(value, list) and bool(value) and all(relative_path(p) for p in value)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def reference(value, snapshot=False):
|
|
22
|
+
# manifest.origin supplies the identity; snapshotOrigin additionally emits
|
|
23
|
+
# normalized path/paths/excludeSnapshots fields on every retained archive.
|
|
24
|
+
if (not isinstance(value, dict) or not isinstance(value.get('repository'), str)
|
|
25
|
+
or not value['repository'] or value['repository'].startswith('-')):
|
|
26
|
+
return False
|
|
27
|
+
if 'projection' in value:
|
|
28
|
+
projection = value['projection']
|
|
29
|
+
if ('revision' in value or not isinstance(projection, dict)
|
|
30
|
+
or set(projection) != {'schemaVersion', 'originalSha256', 'recipeSha256'}
|
|
31
|
+
or type(projection['schemaVersion']) is not int or projection['schemaVersion'] != 1
|
|
32
|
+
or not all(matches(projection[k]) for k in ('originalSha256', 'recipeSha256'))):
|
|
33
|
+
return False
|
|
34
|
+
elif not matches(value.get('revision'), GIT_REVISION):
|
|
35
|
+
return False
|
|
36
|
+
if snapshot and not {'path', 'paths', 'excludeSnapshots'} <= value.keys():
|
|
37
|
+
return False
|
|
38
|
+
return (('path' not in value or value['path'] == '.' or relative_path(value['path']))
|
|
39
|
+
and (value.get('paths') is None or paths(value['paths']))
|
|
40
|
+
and ('excludeSnapshots' not in value or type(value['excludeSnapshots']) is bool))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def file_records(value, archived=False):
|
|
44
|
+
if not isinstance(value, dict):
|
|
45
|
+
return False
|
|
46
|
+
# Payload bytes need not be present elsewhere or agree with a digest.
|
|
47
|
+
# Empty retained file maps are still metadata.
|
|
48
|
+
return all(relative_path(name) and isinstance(record, dict)
|
|
49
|
+
and type(record.get('executable')) is bool
|
|
50
|
+
and (isinstance(record.get('data'), str) if archived else matches(record.get('sha256')))
|
|
51
|
+
for name, record in value.items())
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def archive(value):
|
|
55
|
+
return (isinstance(value, dict) and all(matches(value.get(k)) for k in ('key', 'digest'))
|
|
56
|
+
and reference(value.get('origin'), snapshot=True)
|
|
57
|
+
and file_records(value.get('files'), archived=True)
|
|
58
|
+
and isinstance(value.get('dependencies', []), list)
|
|
59
|
+
and all(pin(dependency) for dependency in value.get('dependencies', [])))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def source(value):
|
|
63
|
+
if not isinstance(value, dict):
|
|
64
|
+
return False
|
|
65
|
+
if value.get('kind') == 'git':
|
|
66
|
+
return reference(value) and relative_path(value.get('destination'))
|
|
67
|
+
if value.get('kind') != 'local' or not paths(value.get('paths')):
|
|
68
|
+
return False
|
|
69
|
+
mappings = value.get('mappings')
|
|
70
|
+
return ((value.get('origin') is None or reference(value['origin']))
|
|
71
|
+
and (mappings is None or (isinstance(mappings, list)
|
|
72
|
+
and all(isinstance(m, dict) and relative_path(m.get('path'))
|
|
73
|
+
and relative_path(m.get('originPath')) for m in mappings))))
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def lock(value):
|
|
77
|
+
if (not isinstance(value, dict) or type(value.get('schemaVersion')) is not int
|
|
78
|
+
or value['schemaVersion'] != 1 or not matches(value.get('edition'), IDENTITY)
|
|
79
|
+
or not matches(value.get('manifest')) or 'parent' not in value
|
|
80
|
+
or (value['parent'] is not None and not pin(value['parent']))
|
|
81
|
+
or not isinstance(value.get('components'), list) or not file_records(value.get('files'))):
|
|
82
|
+
return False
|
|
83
|
+
toolchain = value.get('toolchain')
|
|
84
|
+
if (not isinstance(toolchain, dict) or toolchain.get('id') != 'runeditrun/edition-authoring'
|
|
85
|
+
or not isinstance(toolchain.get('version'), str) or not toolchain['version']
|
|
86
|
+
or not matches(toolchain.get('sha256'))):
|
|
87
|
+
return False
|
|
88
|
+
return all(isinstance(component, dict) and matches(component.get('id'), IDENTITY)
|
|
89
|
+
and source(component.get('source')) and 'baseline' in component
|
|
90
|
+
and (component['baseline'] is None or pin(component['baseline']))
|
|
91
|
+
for component in value['components'])
|
|
@@ -37,8 +37,8 @@ def context(history, commit, config):
|
|
|
37
37
|
'trustBundles': trust}, invalid
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
def text_rules(data, path, config, resolver, env_hashes):
|
|
41
|
-
rules, provenance = inspect(data, path, config, resolver)
|
|
40
|
+
def text_rules(data, path, config, resolver, env_hashes, *, commit_message=False):
|
|
41
|
+
rules, provenance = inspect(data, path, config, resolver, commit_message=commit_message)
|
|
42
42
|
path_rules, _ = inspect(path.encode('utf-8', 'surrogateescape'), '@path', config, resolver)
|
|
43
43
|
rules.update(path_rules)
|
|
44
44
|
if env_hashes and (environment_match(data, env_hashes) or environment_match(path.encode(), env_hashes)):
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
// Reuse the maintained Source serializer; never approximate JSON.stringify in
|
|
2
|
-
// another language. Input and output stay on private subprocess pipes.
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import {hash, json} from '../../edition-authoring/files.mjs';
|
|
5
|
-
const values = JSON.parse(fs.readFileSync(0, 'utf8'));
|
|
6
|
-
process.stdout.write(JSON.stringify(values.map(value => hash(json(value)))));
|