@astrale-os/sdk 0.5.0-beta.90 → 0.5.0-beta.92
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/CHANGELOG.md +14 -0
- package/dist/tooling/cli/arguments.d.ts +1 -0
- package/dist/tooling/cli/arguments.js +11 -2
- package/dist/tooling/cli/development/develop.d.ts +1 -0
- package/dist/tooling/cli/development/develop.js +10 -3
- package/dist/tooling/cli/dotenv.d.ts +2 -0
- package/dist/tooling/cli/dotenv.js +32 -1
- package/dist/tooling/cli/help.js +5 -0
- package/dist/tooling/cli/orchestrate.js +1 -0
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.0-beta.92](https://github.com/astrale-os/sdk/compare/sdk-v0.5.0-beta.91...sdk-v0.5.0-beta.92) (2026-08-30)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **cli:** support supervised development secrets ([#364](https://github.com/astrale-os/sdk/issues/364)) ([2126070](https://github.com/astrale-os/sdk/commit/21260705b059165015238a09abfdeffaf2f7b757))
|
|
9
|
+
|
|
10
|
+
## [0.5.0-beta.91](https://github.com/astrale-os/sdk/compare/sdk-v0.5.0-beta.90...sdk-v0.5.0-beta.91) (2026-08-30)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **deps:** expose endpoint-selective edge policies ([#362](https://github.com/astrale-os/sdk/issues/362)) ([c41a8da](https://github.com/astrale-os/sdk/commit/c41a8da7bfe05eba5a5e59320c6ddedf655f6215))
|
|
16
|
+
|
|
3
17
|
## [0.5.0-beta.90](https://github.com/astrale-os/sdk/compare/sdk-v0.5.0-beta.89...sdk-v0.5.0-beta.90) (2026-08-30)
|
|
4
18
|
|
|
5
19
|
|
|
@@ -10,6 +10,7 @@ export interface ParsedArgs {
|
|
|
10
10
|
readonly host?: string;
|
|
11
11
|
readonly sessionFile?: string;
|
|
12
12
|
readonly credentialFile?: string;
|
|
13
|
+
readonly secretsFile?: string;
|
|
13
14
|
}
|
|
14
15
|
/** Parse the frozen `astrale-domain` command grammar without performing effects. */
|
|
15
16
|
export declare function parseArgs(argv: readonly string[]): ParsedArgs;
|
|
@@ -9,6 +9,7 @@ export function parseArgs(argv) {
|
|
|
9
9
|
let host;
|
|
10
10
|
let sessionFile;
|
|
11
11
|
let credentialFile;
|
|
12
|
+
let secretsFile;
|
|
12
13
|
let format;
|
|
13
14
|
let environment;
|
|
14
15
|
const cleaned = [];
|
|
@@ -45,6 +46,12 @@ export function parseArgs(argv) {
|
|
|
45
46
|
else if (argument.startsWith('--credential-file=')) {
|
|
46
47
|
credentialFile = absoluteFilePath('--credential-file', argument.slice('--credential-file='.length));
|
|
47
48
|
}
|
|
49
|
+
else if (argument === '--secrets-file') {
|
|
50
|
+
secretsFile = absoluteFilePath('--secrets-file', rest[++index]);
|
|
51
|
+
}
|
|
52
|
+
else if (argument.startsWith('--secrets-file=')) {
|
|
53
|
+
secretsFile = absoluteFilePath('--secrets-file', argument.slice('--secrets-file='.length));
|
|
54
|
+
}
|
|
48
55
|
else if (argument === '--format') {
|
|
49
56
|
format = lintFormat(rest[++index]);
|
|
50
57
|
}
|
|
@@ -75,9 +82,10 @@ export function parseArgs(argv) {
|
|
|
75
82
|
if ((port !== undefined ||
|
|
76
83
|
host !== undefined ||
|
|
77
84
|
sessionFile !== undefined ||
|
|
78
|
-
credentialFile !== undefined
|
|
85
|
+
credentialFile !== undefined ||
|
|
86
|
+
secretsFile !== undefined) &&
|
|
79
87
|
command !== 'dev') {
|
|
80
|
-
throw new Error('`--port`, `--host`, `--session-file`, and `--
|
|
88
|
+
throw new Error('`--port`, `--host`, `--session-file`, `--credential-file`, and `--secrets-file` are only valid for `dev`.');
|
|
81
89
|
}
|
|
82
90
|
if (environment !== undefined && !['dev', 'deploy'].includes(command ?? '')) {
|
|
83
91
|
throw new Error('`--environment` is only valid for dev or deploy.');
|
|
@@ -97,6 +105,7 @@ export function parseArgs(argv) {
|
|
|
97
105
|
...(host !== undefined ? { host } : {}),
|
|
98
106
|
...(sessionFile !== undefined ? { sessionFile } : {}),
|
|
99
107
|
...(credentialFile !== undefined ? { credentialFile } : {}),
|
|
108
|
+
...(secretsFile !== undefined ? { secretsFile } : {}),
|
|
100
109
|
};
|
|
101
110
|
case 'deploy': {
|
|
102
111
|
if (positionals.length > 1)
|
|
@@ -4,7 +4,7 @@ import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
|
4
4
|
import { pathToFileURL } from 'node:url';
|
|
5
5
|
import { admitRuntime, compile, isDeployment, resolveRuntime, verifyPreflight, } from '../../../deployment/index.js';
|
|
6
6
|
import { addressing, assemble } from '../../../deployment/release/index.js';
|
|
7
|
-
import { loadDeclaredSecrets } from '../dotenv.js';
|
|
7
|
+
import { loadDeclaredSecrets, loadPrivateSecretsFile } from '../dotenv.js';
|
|
8
8
|
import { error, info } from '../log.js';
|
|
9
9
|
import { DevelopmentLifecycle } from './lifecycle.js';
|
|
10
10
|
import { acquireProjectLock } from './project-lock.js';
|
|
@@ -30,8 +30,11 @@ export async function develop(input) {
|
|
|
30
30
|
projectRoot: input.projectDir,
|
|
31
31
|
environment: input.environment,
|
|
32
32
|
});
|
|
33
|
+
const overrideSecrets = input.secretsFile === undefined
|
|
34
|
+
? undefined
|
|
35
|
+
: Object.freeze(loadPrivateSecretsFile(input.secretsFile));
|
|
33
36
|
const runtimePath = await discoverRuntimePath(input.configPath);
|
|
34
|
-
const builder = new ProjectBuilder({ ...input, runtimePath });
|
|
37
|
+
const builder = new ProjectBuilder({ ...input, runtimePath, overrideSecrets });
|
|
35
38
|
let current = await builder.prepare(lifecycle.signal);
|
|
36
39
|
let sessionEvidence;
|
|
37
40
|
let placementReady = false;
|
|
@@ -261,12 +264,14 @@ class ProjectBuilder {
|
|
|
261
264
|
#projectDir;
|
|
262
265
|
#environment;
|
|
263
266
|
#runtimePath;
|
|
267
|
+
#overrideSecrets;
|
|
264
268
|
#generation = 0;
|
|
265
269
|
constructor(input) {
|
|
266
270
|
this.#configPath = input.configPath;
|
|
267
271
|
this.#projectDir = input.projectDir;
|
|
268
272
|
this.#environment = input.environment;
|
|
269
273
|
this.#runtimePath = input.runtimePath;
|
|
274
|
+
this.#overrideSecrets = input.overrideSecrets;
|
|
270
275
|
}
|
|
271
276
|
async prepare(signal) {
|
|
272
277
|
throwIfAborted(signal);
|
|
@@ -320,7 +325,9 @@ class ProjectBuilder {
|
|
|
320
325
|
runtime: resolved,
|
|
321
326
|
});
|
|
322
327
|
const artifact = verifyPreflight({ build, runtime: resolved, source });
|
|
323
|
-
const declared =
|
|
328
|
+
const declared = this.#overrideSecrets === undefined
|
|
329
|
+
? secretsFor(adapter, parameters, this.#projectDir, resolved.runtime)
|
|
330
|
+
: { values: this.#overrideSecrets };
|
|
324
331
|
const sources = new Set();
|
|
325
332
|
for (const path of Object.keys(built.metafile?.inputs ?? {})) {
|
|
326
333
|
const absolute = isAbsolute(path) ? path : resolve(this.#projectDir, path);
|
|
@@ -15,3 +15,5 @@
|
|
|
15
15
|
* that exists but holds no keys is legitimate (a domain with no secrets yet).
|
|
16
16
|
*/
|
|
17
17
|
export declare function loadDeclaredSecrets(path: string, declaration: string): Record<string, string>;
|
|
18
|
+
/** Load one explicit development-session secret snapshot without following a leaf symlink. */
|
|
19
|
+
export declare function loadPrivateSecretsFile(path: string, platform?: NodeJS.Platform): Record<string, string>;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* runtime in dev, pushed to a secret store in prod). No `process.env` mutation,
|
|
8
8
|
* no interpolation magic beyond `${VAR}` against earlier keys in the same file.
|
|
9
9
|
*/
|
|
10
|
-
import { readFileSync } from 'node:fs';
|
|
10
|
+
import { closeSync, constants, fstatSync, openSync, readFileSync } from 'node:fs';
|
|
11
11
|
function parseDotenv(contents) {
|
|
12
12
|
const out = {};
|
|
13
13
|
for (const raw of contents.split('\n')) {
|
|
@@ -52,3 +52,34 @@ export function loadDeclaredSecrets(path, declaration) {
|
|
|
52
52
|
}
|
|
53
53
|
return parseDotenv(contents);
|
|
54
54
|
}
|
|
55
|
+
/** Load one explicit development-session secret snapshot without following a leaf symlink. */
|
|
56
|
+
export function loadPrivateSecretsFile(path, platform = process.platform) {
|
|
57
|
+
if (platform === 'win32') {
|
|
58
|
+
throw new Error('--secrets-file is unavailable on Windows until private no-reparse file admission is supported.');
|
|
59
|
+
}
|
|
60
|
+
let descriptor;
|
|
61
|
+
try {
|
|
62
|
+
descriptor = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
63
|
+
}
|
|
64
|
+
catch (cause) {
|
|
65
|
+
if (cause instanceof Error && 'code' in cause && cause.code === 'ENOENT') {
|
|
66
|
+
throw new Error(`Secrets file '${path}' is missing.`, { cause });
|
|
67
|
+
}
|
|
68
|
+
if (cause instanceof Error && 'code' in cause && cause.code === 'ELOOP') {
|
|
69
|
+
throw new Error(`Secrets file '${path}' must be a regular file and not a symlink.`, { cause });
|
|
70
|
+
}
|
|
71
|
+
throw cause;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const info = fstatSync(descriptor);
|
|
75
|
+
if (!info.isFile())
|
|
76
|
+
throw new Error(`Secrets file '${path}' must be a regular file.`);
|
|
77
|
+
if ((info.mode & 0o077) !== 0) {
|
|
78
|
+
throw new Error(`Secrets file '${path}' must not be accessible by group or other users.`);
|
|
79
|
+
}
|
|
80
|
+
return parseDotenv(readFileSync(descriptor, 'utf8'));
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
closeSync(descriptor);
|
|
84
|
+
}
|
|
85
|
+
}
|
package/dist/tooling/cli/help.js
CHANGED
|
@@ -48,6 +48,8 @@ Options:
|
|
|
48
48
|
--credential-file <path>
|
|
49
49
|
Use one private operator credential for adapter-owned Kernel
|
|
50
50
|
calls without exposing it in project configuration.
|
|
51
|
+
--secrets-file <path> Load one private, absolute secrets file for this development
|
|
52
|
+
session instead of the adapter-declared secrets file.
|
|
51
53
|
-h, --help Show help for dev.
|
|
52
54
|
|
|
53
55
|
Behavior:
|
|
@@ -61,6 +63,9 @@ Behavior:
|
|
|
61
63
|
installed Release evidence.
|
|
62
64
|
A credential file is read only by the installation-owning adapter. Its value is
|
|
63
65
|
never forwarded to the Domain runtime or written to the session file.
|
|
66
|
+
A secrets-file override is read once, passed to the Domain runtime as secrets,
|
|
67
|
+
never mutates the authored project, and is not watched for later changes. It is
|
|
68
|
+
currently unavailable on Windows because private no-reparse admission is absent.
|
|
64
69
|
|
|
65
70
|
Adapters:
|
|
66
71
|
cloudflare Runs the local Worker and optional Vite frontend only;
|
|
@@ -97,6 +97,7 @@ export function executeDevelopmentCommand(parsed, input, execute = develop) {
|
|
|
97
97
|
...(parsed.credentialFile === undefined ? {} : { credentialFile: parsed.credentialFile }),
|
|
98
98
|
}),
|
|
99
99
|
...(parsed.sessionFile === undefined ? {} : { sessionFile: parsed.sessionFile }),
|
|
100
|
+
...(parsed.secretsFile === undefined ? {} : { secretsFile: parsed.secretsFile }),
|
|
100
101
|
});
|
|
101
102
|
}
|
|
102
103
|
async function lint(parsed) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrale-os/sdk",
|
|
3
|
-
"version": "0.5.0-beta.
|
|
3
|
+
"version": "0.5.0-beta.92",
|
|
4
4
|
"description": "Schema-first SDK for defining, composing, and deploying Astrale domains",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astrale",
|
|
@@ -217,11 +217,11 @@
|
|
|
217
217
|
"registry": "https://registry.npmjs.org/"
|
|
218
218
|
},
|
|
219
219
|
"dependencies": {
|
|
220
|
-
"@astrale-os/kernel-client": "0.6.0-beta.
|
|
221
|
-
"@astrale-os/kernel-core": "0.9.0-beta.
|
|
222
|
-
"@astrale-os/kernel-dsl": "0.2.0-beta.
|
|
223
|
-
"@astrale-os/kernel-protocol": "0.5.0-beta.
|
|
224
|
-
"@astrale-os/kernel-server": "0.5.0-beta.
|
|
220
|
+
"@astrale-os/kernel-client": "0.6.0-beta.35",
|
|
221
|
+
"@astrale-os/kernel-core": "0.9.0-beta.27",
|
|
222
|
+
"@astrale-os/kernel-dsl": "0.2.0-beta.20",
|
|
223
|
+
"@astrale-os/kernel-protocol": "0.5.0-beta.28",
|
|
224
|
+
"@astrale-os/kernel-server": "0.5.0-beta.30",
|
|
225
225
|
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
226
226
|
"hono": "^4.13.2",
|
|
227
227
|
"jose": "^6.2.9",
|