@sibylline-labs/eris 0.0.0-stage → 0.3.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 +202 -0
- package/NOTICE +2 -0
- package/README.md +146 -2
- package/bin/eris.ts +42 -0
- package/docs/ARCHITECTURE.md +188 -0
- package/docs/COMPLETION.md +106 -0
- package/docs/ERRORS.md +632 -0
- package/docs/OUTPUT-CONTRACT.md +219 -0
- package/docs/README.md +30 -0
- package/docs/UPDATE.md +159 -0
- package/docs/YAK.md +395 -0
- package/docs/dev/ADDING-A-COMMAND.md +79 -0
- package/docs/dev/DEVELOPMENT.md +88 -0
- package/docs/dev/LAYOUT.md +74 -0
- package/docs/dev/PLUGINS.md +382 -0
- package/docs/dev/RELEASING.md +157 -0
- package/docs/dev/TESTING.md +84 -0
- package/docs/dev/surfaces/secrets.md +95 -0
- package/package.json +55 -4
- package/packages/yak-contract/package.json +28 -0
- package/packages/yak-contract/schema/yak-v2.schema.json +416 -0
- package/packages/yak-contract/src/index.ts +1 -0
- package/packages/yak-contract/src/v2.ts +375 -0
- package/plugins/index.ts +12 -0
- package/plugins/yak/handlers.ts +128 -0
- package/plugins/yak/index.ts +51 -0
- package/plugins/yak/login.ts +300 -0
- package/plugins/yak/yak-context.ts +280 -0
- package/plugins/yak/yak-identity.ts +399 -0
- package/plugins/yak/yak-redact.ts +686 -0
- package/plugins/yak/yak-setup.ts +133 -0
- package/plugins/yak/yak-submit.ts +1166 -0
- package/plugins/yak/yak.ts +485 -0
- package/src/build.ts +248 -0
- package/src/cli/args.ts +434 -0
- package/src/cli/commands/completion/bash.ts +24 -0
- package/src/cli/commands/completion/domain.ts +203 -0
- package/src/cli/commands/completion/emit.ts +246 -0
- package/src/cli/commands/completion/shell.ts +24 -0
- package/src/cli/commands/completion/zsh.ts +24 -0
- package/src/cli/commands/completion.ts +48 -0
- package/src/cli/commands/update/github.ts +328 -0
- package/src/cli/commands/update/opt-in.ts +32 -0
- package/src/cli/commands/update/refusal.ts +21 -0
- package/src/cli/commands/update/release.ts +351 -0
- package/src/cli/commands/update/replace.ts +143 -0
- package/src/cli/commands/update/semver.ts +48 -0
- package/src/cli/commands/update.ts +47 -0
- package/src/cli/commands/usage.ts +68 -0
- package/src/cli/commands/version.ts +29 -0
- package/src/cli/compose.ts +273 -0
- package/src/cli/output.ts +81 -0
- package/src/cli/plugin.ts +85 -0
- package/src/cli/registry.ts +180 -0
- package/src/cli/router.ts +31 -0
- package/src/cli/ts-verb.ts +126 -0
- package/src/main.ts +223 -0
- package/src/runtime/env.ts +16 -0
- package/src/runtime/eris-assets.d.ts +5 -0
- package/src/runtime/home.ts +306 -0
- package/src/runtime/logging.ts +43 -0
- package/src/runtime/process.ts +388 -0
- package/src/runtime/settings.ts +191 -0
- package/src/sdk.ts +62 -0
- package/testing/build-child.ts +55 -0
- package/testing/fake-runner.ts +23 -0
- package/testing/index.ts +16 -0
- package/ts/lib/eris-fail.ts +180 -0
- package/ts/lib/pool.ts +63 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* yak-setup.ts — mint this machine's Yaks bearer and write ~/.eris/yaks.json.
|
|
4
|
+
*
|
|
5
|
+
* `eris yak` reads its URL and bearer from ONE file, ~/.eris/yaks.json, mode
|
|
6
|
+
* 0600 (ERIS_YAKS_URL / ERIS_YAKS_TOKEN override each field). The file lives
|
|
7
|
+
* outside every repository on purpose: a per-source token IS the ingest
|
|
8
|
+
* identity, and a repo file is committed. A private file in $HOME is not that,
|
|
9
|
+
* but only while it stays 0600, so the file is created at 0600 here and the
|
|
10
|
+
* reader REFUSES a group- or world-readable one.
|
|
11
|
+
*
|
|
12
|
+
* The URL comes from `resolveUrl` (--url, then ERIS_YAKS_URL). The script
|
|
13
|
+
* refuses when that falls to the built-in default: that endpoint signs a
|
|
14
|
+
* machine in with `eris login` and registers no hand-minted bearer.
|
|
15
|
+
*
|
|
16
|
+
* THIS SCRIPT DOES HALF THE JOB. The token it mints is meaningless until the
|
|
17
|
+
* endpoint's operator registers it against the `source` slug stamped on every
|
|
18
|
+
* observation. That half belongs to the operator and is not automated here.
|
|
19
|
+
* The final message prints the entry to hand over. The token itself is never
|
|
20
|
+
* printed.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { randomBytes } from "node:crypto";
|
|
24
|
+
import { existsSync, mkdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
25
|
+
import { homedir, hostname } from "node:os";
|
|
26
|
+
import { join } from "node:path";
|
|
27
|
+
import { readArgs } from "../../src/cli/plugin";
|
|
28
|
+
import { resolveUrl } from "./yak-identity";
|
|
29
|
+
|
|
30
|
+
const USAGE_LINE = "plugins/yak/yak-setup.ts [--slug <slug>] [--url <url>] [--force]";
|
|
31
|
+
/** Not an eris verb, so not in the manifest: the one parser reads this row directly. */
|
|
32
|
+
const ROWS = {
|
|
33
|
+
"yak-setup": {
|
|
34
|
+
summary: "Mint this machine's Yaks bearer",
|
|
35
|
+
flags: [
|
|
36
|
+
{ name: "--slug", takesValue: true },
|
|
37
|
+
{ name: "--url", takesValue: true },
|
|
38
|
+
{ name: "--force", takesValue: false },
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
} as const;
|
|
42
|
+
const USAGE = `Usage: ${USAGE_LINE}
|
|
43
|
+
|
|
44
|
+
Mint this machine's Yaks bearer and write ~/.eris/yaks.json at mode 0600.
|
|
45
|
+
|
|
46
|
+
--slug <slug> the source slug the bearer maps to (default: yak-<hostname>)
|
|
47
|
+
--url <url> the Yaks endpoint base URL (default: $ERIS_YAKS_URL; one
|
|
48
|
+
of the two is required)
|
|
49
|
+
--force overwrite an existing ~/.eris/yaks.json (mints a NEW bearer;
|
|
50
|
+
the old one stays live until the operator removes it)
|
|
51
|
+
|
|
52
|
+
The bearer works only once the endpoint's operator has registered it; the
|
|
53
|
+
entry to send them is printed after the file is written.
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
/** `hostname -s`, lowercased, every byte outside [a-z0-9._-] made '-', trailing '-' dropped. */
|
|
57
|
+
function defaultSlug(): string {
|
|
58
|
+
const short = hostname().split(".")[0] ?? "";
|
|
59
|
+
return `yak-${short.toLowerCase().replace(/[^a-z0-9._-]/g, "-").replace(/-+$/, "")}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** The `ls -l` mode string of a regular file. */
|
|
63
|
+
function modeString(path: string): string {
|
|
64
|
+
const m = statSync(path).mode;
|
|
65
|
+
const bits = "rwxrwxrwx";
|
|
66
|
+
return `-${[...bits].map((c, i) => (m & (1 << (8 - i)) ? c : "-")).join("")}`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function fail(msg: string): never {
|
|
70
|
+
process.stderr.write(`${msg}\n`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function main(
|
|
75
|
+
argv: string[],
|
|
76
|
+
home: string = process.env.HOME ?? homedir(),
|
|
77
|
+
env: Record<string, string | undefined> = process.env,
|
|
78
|
+
): number {
|
|
79
|
+
const io = { erisDir: "", stdout: process.stdout, stderr: process.stderr };
|
|
80
|
+
const p = readArgs(ROWS, "yak-setup", argv, io, {
|
|
81
|
+
help: USAGE,
|
|
82
|
+
refuse: (_e, what) => fail(`${what.charAt(0).toUpperCase()}${what.slice(1)} (usage: ${USAGE_LINE})`),
|
|
83
|
+
});
|
|
84
|
+
if (p === null) return 0;
|
|
85
|
+
const slug = p.flags["--slug"] ?? defaultSlug();
|
|
86
|
+
const resolved = resolveUrl({}, env, p.flags["--url"]);
|
|
87
|
+
if (resolved.source === "default") {
|
|
88
|
+
fail(`no Yaks URL: pass --url <url> or set ERIS_YAKS_URL (usage: ${USAGE_LINE})\n for ${resolved.value}, run 'eris login' instead`);
|
|
89
|
+
}
|
|
90
|
+
const url = resolved.value;
|
|
91
|
+
const force = p.flags["--force"];
|
|
92
|
+
|
|
93
|
+
// The registry's own grammar for a source slug.
|
|
94
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/.test(slug)) fail(`slug '${slug}' fails the registry grammar ^[a-z0-9][a-z0-9._-]*$`);
|
|
95
|
+
|
|
96
|
+
const dir = join(home, ".eris");
|
|
97
|
+
const dest = join(dir, "yaks.json");
|
|
98
|
+
if (existsSync(dest) && !force) {
|
|
99
|
+
fail(
|
|
100
|
+
`refusing to overwrite ${dest} (pass --force if that is what you want)\n` +
|
|
101
|
+
" a rewrite mints a NEW bearer, and the old one keeps working until it is\n" +
|
|
102
|
+
" removed by the endpoint's operator — you would be leaving a live key behind.",
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 256 bits. The temp file is CREATED at 0600 (never chmod-after-write, which
|
|
107
|
+
// leaves a readable window on credential material), then renamed so a reader
|
|
108
|
+
// never sees a half-written file.
|
|
109
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
110
|
+
const token = randomBytes(32).toString("hex");
|
|
111
|
+
const tmp = `${dest}.tmp.${process.pid}`;
|
|
112
|
+
try {
|
|
113
|
+
writeFileSync(tmp, `{\n "url": "${url}",\n "token": "${token}"\n}\n`, { mode: 0o600, flag: "wx" });
|
|
114
|
+
renameSync(tmp, dest);
|
|
115
|
+
} finally {
|
|
116
|
+
rmSync(tmp, { force: true });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
process.stdout.write(
|
|
120
|
+
`wrote ${dest} (${modeString(dest)})
|
|
121
|
+
|
|
122
|
+
NEXT — the half this script cannot do. The bearer works only once
|
|
123
|
+
the operator of ${url} registers it against this machine's source
|
|
124
|
+
slug. Send them this entry over a private channel (the token is in
|
|
125
|
+
${dest} — it is not reprinted here):
|
|
126
|
+
|
|
127
|
+
"<token from ${dest}>": "${slug}"
|
|
128
|
+
`,
|
|
129
|
+
);
|
|
130
|
+
return 0;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (import.meta.main) process.exitCode = main(process.argv.slice(2));
|