runnix 0.4.0-rc.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 +661 -0
- package/README.md +48 -0
- package/bin/runnix.mjs +9 -0
- package/dist/deploy-logic.js +92 -0
- package/dist/deploy-logic.js.map +1 -0
- package/dist/image-digest.js +142 -0
- package/dist/image-digest.js.map +1 -0
- package/dist/main.js +475 -0
- package/dist/main.js.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# runnix
|
|
2
|
+
|
|
3
|
+
Command-line tool for [Runnix](https://runnix.run), the PostgreSQL-native
|
|
4
|
+
workflow orchestration platform: deploy runsets with their worker images,
|
|
5
|
+
verify worker builds, inspect deploys, promote rollbacks.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g runnix # or: npx runnix <command>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Node 22+. The CLI loads `runnix.config.ts` and your TypeScript function
|
|
12
|
+
modules directly; your project needs no build step.
|
|
13
|
+
|
|
14
|
+
## Commands
|
|
15
|
+
|
|
16
|
+
| Command | What it does |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| `runnix deploy` | Discover functions, resolve runsets and post the manifests. `--image <ref>` (or `image` in `runnix.config.ts`) names the worker image; the digest is resolved from your own `docker` after the push. Records git and CI provenance on the deploy. |
|
|
19
|
+
| `runnix verify` | Build/startup guard: checks a worker build carries exactly one runset's complete, current function set. `--offline` skips the control-plane comparison. |
|
|
20
|
+
| `runnix deployments` | Current deployment per runset. `--history [n]` lists recent deploys with every runset each shipped. |
|
|
21
|
+
| `runnix promote --to <deploymentId>` | Roll a runset back (or forward) by replaying a previous deployment's snapshot as a new one. |
|
|
22
|
+
| `runnix init` | Scaffold a project. |
|
|
23
|
+
| `runnix functions list`, `runnix test <id>` | Local discovery and execution without a control plane. |
|
|
24
|
+
|
|
25
|
+
Remote commands read `RUNNIX_URL` and `RUNNIX_API_KEY` (a deploy-scoped key)
|
|
26
|
+
from the environment, or take `--url`.
|
|
27
|
+
|
|
28
|
+
## CI order
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
runnix verify --offline
|
|
32
|
+
docker build -t ghcr.io/acme/billing:$SHA . && docker push ghcr.io/acme/billing:$SHA
|
|
33
|
+
runnix deploy --image ghcr.io/acme/billing:$SHA --version $SHA
|
|
34
|
+
runnix verify
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Production-type environments refuse an image with no resolvable digest unless
|
|
38
|
+
you pass `--allow-unpinned`.
|
|
39
|
+
|
|
40
|
+
## Documentation
|
|
41
|
+
|
|
42
|
+
- Runsets and deploys: https://runnix.run/docs/runsets
|
|
43
|
+
- Self-hosted worker pools: https://runnix.run/docs/worker-pool
|
|
44
|
+
|
|
45
|
+
## License
|
|
46
|
+
|
|
47
|
+
AGPL-3.0-or-later. The SDK you import into your functions (`@runnix/sdk`) is
|
|
48
|
+
Apache-2.0.
|
package/bin/runnix.mjs
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Runnix CLI entry. Registers tsx's ESM loader before loading the compiled
|
|
3
|
+
// CLI so `runnix.config.ts` and the project's TypeScript function modules can
|
|
4
|
+
// be imported directly - the user's project needs no build step and no
|
|
5
|
+
// `--experimental-strip-types` (which cannot resolve extensionless imports).
|
|
6
|
+
import { register } from 'tsx/esm/api'
|
|
7
|
+
|
|
8
|
+
register()
|
|
9
|
+
await import('../dist/main.js')
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/** Local check: every discovered function must resolve to `runset`. */
|
|
2
|
+
export function checkSingleRunset(functions, runset) {
|
|
3
|
+
return functions
|
|
4
|
+
.filter((fn) => fn.runset !== runset)
|
|
5
|
+
.map((fn) => ({
|
|
6
|
+
kind: 'mixed-runset',
|
|
7
|
+
identifier: fn.definition.identifier,
|
|
8
|
+
detail: `resolves to runset "${fn.runset}" but this build is verified as "${runset}" (${fn.modulePath})`,
|
|
9
|
+
}));
|
|
10
|
+
}
|
|
11
|
+
/** Remote check: the build must match the runset's deployed manifest exactly. */
|
|
12
|
+
export function compareAgainstManifest(local, deployed) {
|
|
13
|
+
const problems = [];
|
|
14
|
+
const localByIdentifier = new Map(local.map((fn) => [fn.identifier, fn.definitionHash]));
|
|
15
|
+
const deployedByIdentifier = new Map(deployed.map((fn) => [fn.identifier, fn.definitionHash]));
|
|
16
|
+
for (const [identifier, hash] of deployedByIdentifier) {
|
|
17
|
+
const localHash = localByIdentifier.get(identifier);
|
|
18
|
+
if (localHash === undefined) {
|
|
19
|
+
problems.push({
|
|
20
|
+
kind: 'missing',
|
|
21
|
+
identifier,
|
|
22
|
+
detail: 'deployed in this runset but absent from the build (partial image)',
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
else if (localHash !== hash) {
|
|
26
|
+
problems.push({
|
|
27
|
+
kind: 'hash-mismatch',
|
|
28
|
+
identifier,
|
|
29
|
+
detail: `build carries ${localHash.slice(0, 12)}, deployment expects ${hash.slice(0, 12)} (stale or unreleased build)`,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
for (const identifier of localByIdentifier.keys()) {
|
|
34
|
+
if (!deployedByIdentifier.has(identifier)) {
|
|
35
|
+
problems.push({
|
|
36
|
+
kind: 'undeployed',
|
|
37
|
+
identifier,
|
|
38
|
+
detail: 'present in the build but not in the deployed manifest (deploy before shipping the image)',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return problems.sort((a, b) => a.identifier.localeCompare(b.identifier));
|
|
43
|
+
}
|
|
44
|
+
export function partitionByRunset(functions, owned) {
|
|
45
|
+
const byIdentifier = new Map();
|
|
46
|
+
const duplicates = new Map();
|
|
47
|
+
for (const fn of functions) {
|
|
48
|
+
const id = fn.definition.identifier;
|
|
49
|
+
const existing = byIdentifier.get(id);
|
|
50
|
+
if (!existing) {
|
|
51
|
+
byIdentifier.set(id, fn);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
// Re-exports of the same build are harmless; different hashes are a bug.
|
|
55
|
+
if (existing.definitionHash !== fn.definitionHash || existing.runset !== fn.runset) {
|
|
56
|
+
const set = duplicates.get(id) ?? new Set([existing.modulePath]);
|
|
57
|
+
set.add(fn.modulePath);
|
|
58
|
+
duplicates.set(id, set);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const byRunset = new Map();
|
|
62
|
+
for (const fn of byIdentifier.values()) {
|
|
63
|
+
const list = byRunset.get(fn.runset) ?? [];
|
|
64
|
+
list.push(fn);
|
|
65
|
+
byRunset.set(fn.runset, list);
|
|
66
|
+
}
|
|
67
|
+
const body = {
|
|
68
|
+
runsets: [...byRunset.entries()]
|
|
69
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
70
|
+
.map(([runset, fns]) => ({
|
|
71
|
+
runset,
|
|
72
|
+
functions: fns
|
|
73
|
+
.sort((a, b) => a.definition.identifier.localeCompare(b.definition.identifier))
|
|
74
|
+
.map((fn) => ({
|
|
75
|
+
definition: fn.definition,
|
|
76
|
+
definitionHash: fn.definitionHash,
|
|
77
|
+
region: fn.region,
|
|
78
|
+
requiredEnv: fn.requiredEnv,
|
|
79
|
+
})),
|
|
80
|
+
})),
|
|
81
|
+
};
|
|
82
|
+
if (owned && owned.length > 0)
|
|
83
|
+
body.owned = owned;
|
|
84
|
+
return {
|
|
85
|
+
body,
|
|
86
|
+
duplicates: [...duplicates.entries()].map(([identifier, modules]) => ({
|
|
87
|
+
identifier,
|
|
88
|
+
modules: [...modules].sort(),
|
|
89
|
+
})),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=deploy-logic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy-logic.js","sourceRoot":"","sources":["../src/deploy-logic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { parseImageReference, sameRepository } from '@runnix/protocol';
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
/** Image cascade (Decision #24): --image > runsets[x].image > config.image > none. */
|
|
6
|
+
export function resolveImage(input) {
|
|
7
|
+
return input.flag ?? input.config.runsets?.[input.runset]?.image ?? input.config.image;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* From `docker image inspect --format '{{json .RepoDigests}}'`: the digest
|
|
11
|
+
* for THIS repository - an image tagged into several repositories carries
|
|
12
|
+
* one RepoDigest per repository, and only the matching one is the pinned
|
|
13
|
+
* generation the pool will pull.
|
|
14
|
+
*/
|
|
15
|
+
export function pickRepoDigest(repoDigests, reference) {
|
|
16
|
+
for (const entry of repoDigests) {
|
|
17
|
+
const at = entry.indexOf('@');
|
|
18
|
+
if (at === -1)
|
|
19
|
+
continue;
|
|
20
|
+
if (sameRepository(entry.slice(0, at), reference))
|
|
21
|
+
return entry.slice(at + 1);
|
|
22
|
+
}
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Resolve the pushed digest for a reference using the developer's local
|
|
27
|
+
* docker (their login - the control plane never touches a registry). First
|
|
28
|
+
* hit wins: an explicit digest, a digest in the reference, the local
|
|
29
|
+
* image's RepoDigests, then the registry via buildx imagetools. Undefined
|
|
30
|
+
* when nothing resolves (not built/pushed yet, or no docker at all).
|
|
31
|
+
*/
|
|
32
|
+
export async function resolveDigest(reference, explicit) {
|
|
33
|
+
if (explicit)
|
|
34
|
+
return explicit;
|
|
35
|
+
const parsed = parseImageReference(reference);
|
|
36
|
+
if (parsed?.digest)
|
|
37
|
+
return parsed.digest;
|
|
38
|
+
try {
|
|
39
|
+
const { stdout } = await execFileAsync('docker', [
|
|
40
|
+
'image',
|
|
41
|
+
'inspect',
|
|
42
|
+
'--format',
|
|
43
|
+
'{{json .RepoDigests}}',
|
|
44
|
+
reference,
|
|
45
|
+
]);
|
|
46
|
+
const digest = pickRepoDigest(JSON.parse(stdout.trim()), reference);
|
|
47
|
+
if (digest)
|
|
48
|
+
return digest;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Not local (or no docker): try the registry.
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const { stdout } = await execFileAsync('docker', [
|
|
55
|
+
'buildx',
|
|
56
|
+
'imagetools',
|
|
57
|
+
'inspect',
|
|
58
|
+
reference,
|
|
59
|
+
'--format',
|
|
60
|
+
'{{.Manifest.Digest}}',
|
|
61
|
+
]);
|
|
62
|
+
const digest = stdout.trim();
|
|
63
|
+
if (/^sha256:[a-f0-9]{64}$/.test(digest))
|
|
64
|
+
return digest;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Unreachable registry, or not pushed.
|
|
68
|
+
}
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
/** Short git SHA as the default deployment version label; undefined outside a repo. */
|
|
72
|
+
export async function gitShortSha() {
|
|
73
|
+
try {
|
|
74
|
+
const { stdout } = await execFileAsync('git', ['rev-parse', '--short=12', 'HEAD']);
|
|
75
|
+
return stdout.trim() || undefined;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** Strip embedded credentials from a remote URL (`https://user:token@host/...` is common in CI). */
|
|
82
|
+
export function redactRemote(url) {
|
|
83
|
+
return url.replace(/^(\w+:\/\/)[^@/]+@/, '$1');
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Best-effort git provenance for the deploy record (Decision #25): sha,
|
|
87
|
+
* branch, dirty flag, remote, subject line. Undefined outside a repository;
|
|
88
|
+
* every field beyond the sha is optional so a shallow CI checkout still
|
|
89
|
+
* yields a record.
|
|
90
|
+
*/
|
|
91
|
+
export async function gitMetadata(cwd = process.cwd()) {
|
|
92
|
+
const run = async (args) => (await execFileAsync('git', args, { cwd })).stdout.trim();
|
|
93
|
+
let sha;
|
|
94
|
+
try {
|
|
95
|
+
sha = await run(['rev-parse', 'HEAD']);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
if (!/^[0-9a-f]{7,64}$/.test(sha))
|
|
101
|
+
return undefined;
|
|
102
|
+
const out = { sha };
|
|
103
|
+
const ignore = () => { };
|
|
104
|
+
await Promise.all([
|
|
105
|
+
run(['rev-parse', '--abbrev-ref', 'HEAD']).then((branch) => {
|
|
106
|
+
if (branch && branch !== 'HEAD')
|
|
107
|
+
out.branch = branch.slice(0, 200);
|
|
108
|
+
}, ignore),
|
|
109
|
+
run(['status', '--porcelain']).then((status) => {
|
|
110
|
+
out.dirty = status.length > 0;
|
|
111
|
+
}, ignore),
|
|
112
|
+
run(['remote', 'get-url', 'origin']).then((remote) => {
|
|
113
|
+
if (remote)
|
|
114
|
+
out.remote = redactRemote(remote).slice(0, 300);
|
|
115
|
+
}, ignore),
|
|
116
|
+
run(['log', '-1', '--pretty=%s']).then((message) => {
|
|
117
|
+
if (message)
|
|
118
|
+
out.message = message.slice(0, 200);
|
|
119
|
+
}, ignore),
|
|
120
|
+
]);
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
/** CI run provenance from the well-known environment variables; undefined outside CI. */
|
|
124
|
+
export function ciMetadata(env = process.env) {
|
|
125
|
+
const withUrl = (provider, runUrl) => runUrl ? { provider, runUrl: runUrl.slice(0, 500) } : { provider };
|
|
126
|
+
if (env.GITHUB_ACTIONS === 'true') {
|
|
127
|
+
const runUrl = env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY && env.GITHUB_RUN_ID
|
|
128
|
+
? `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${env.GITHUB_RUN_ID}`
|
|
129
|
+
: undefined;
|
|
130
|
+
return withUrl('github', runUrl);
|
|
131
|
+
}
|
|
132
|
+
if (env.GITLAB_CI === 'true')
|
|
133
|
+
return withUrl('gitlab', env.CI_JOB_URL);
|
|
134
|
+
if (env.CIRCLECI === 'true')
|
|
135
|
+
return withUrl('circleci', env.CIRCLE_BUILD_URL);
|
|
136
|
+
if (env.BUILDKITE === 'true')
|
|
137
|
+
return withUrl('buildkite', env.BUILDKITE_BUILD_URL);
|
|
138
|
+
if (env.CI)
|
|
139
|
+
return { provider: 'ci' };
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=image-digest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-digest.js","sourceRoot":"","sources":["../src/image-digest.ts"],"names":[],"mappings":"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"}
|