looply-cli 0.5.22 → 0.5.24
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/dist/.src-hash +1 -1
- package/dist/branch-delivery-wiring.d.ts.map +1 -1
- package/dist/branch-delivery-wiring.js +9 -2
- package/dist/branch-delivery-wiring.js.map +1 -1
- package/dist/branch-delivery.d.ts.map +1 -1
- package/dist/branch-delivery.js +17 -2
- package/dist/branch-delivery.js.map +1 -1
- package/dist/config.d.ts +9 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +14 -0
- package/dist/config.js.map +1 -1
- package/dist/daemon-cmd.d.ts +2 -0
- package/dist/daemon-cmd.d.ts.map +1 -1
- package/dist/daemon-cmd.js +37 -0
- package/dist/daemon-cmd.js.map +1 -1
- package/dist/eas-cli-install.d.ts +47 -0
- package/dist/eas-cli-install.d.ts.map +1 -0
- package/dist/eas-cli-install.js +148 -0
- package/dist/eas-cli-install.js.map +1 -0
- package/dist/expo-release-wiring.d.ts +4 -1
- package/dist/expo-release-wiring.d.ts.map +1 -1
- package/dist/expo-release-wiring.js +19 -1
- package/dist/expo-release-wiring.js.map +1 -1
- package/dist/expo-release.d.ts +6 -1
- package/dist/expo-release.d.ts.map +1 -1
- package/dist/expo-release.js +11 -2
- package/dist/expo-release.js.map +1 -1
- package/dist/feature-report.d.ts +25 -0
- package/dist/feature-report.d.ts.map +1 -0
- package/dist/feature-report.js +112 -0
- package/dist/feature-report.js.map +1 -0
- package/dist/feature-settings-cache.d.ts +39 -0
- package/dist/feature-settings-cache.d.ts.map +1 -0
- package/dist/feature-settings-cache.js +124 -0
- package/dist/feature-settings-cache.js.map +1 -0
- package/dist/machine-secrets.d.ts +65 -0
- package/dist/machine-secrets.d.ts.map +1 -0
- package/dist/machine-secrets.js +237 -0
- package/dist/machine-secrets.js.map +1 -0
- package/dist/preview-wiring.d.ts +2 -0
- package/dist/preview-wiring.d.ts.map +1 -1
- package/dist/preview-wiring.js +21 -2
- package/dist/preview-wiring.js.map +1 -1
- package/dist/remote-command.d.ts +34 -0
- package/dist/remote-command.d.ts.map +1 -0
- package/dist/remote-command.js +37 -0
- package/dist/remote-command.js.map +1 -0
- package/dist/run-cmd.d.ts.map +1 -1
- package/dist/run-cmd.js +8 -1
- package/dist/run-cmd.js.map +1 -1
- package/dist/server-client.d.ts +34 -1
- package/dist/server-client.d.ts.map +1 -1
- package/dist/server-client.js +32 -0
- package/dist/server-client.js.map +1 -1
- package/dist/untrusted-gate.d.ts +10 -1
- package/dist/untrusted-gate.d.ts.map +1 -1
- package/dist/untrusted-gate.js +2 -2
- package/dist/untrusted-gate.js.map +1 -1
- package/dist/visual-proof-cmd.d.ts.map +1 -1
- package/dist/visual-proof-cmd.js +6 -2
- package/dist/visual-proof-cmd.js.map +1 -1
- package/dist/visual-proof-detect.d.ts +29 -0
- package/dist/visual-proof-detect.d.ts.map +1 -0
- package/dist/visual-proof-detect.js +278 -0
- package/dist/visual-proof-detect.js.map +1 -0
- package/dist/visual-proof-run.d.ts.map +1 -1
- package/dist/visual-proof-run.js +6 -2
- package/dist/visual-proof-run.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isExpoProject = isExpoProject;
|
|
4
|
+
exports.expoTokenState = expoTokenState;
|
|
5
|
+
exports.buildFeatureReport = buildFeatureReport;
|
|
6
|
+
exports.makeFeatureReporter = makeFeatureReporter;
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_path_1 = require("node:path");
|
|
10
|
+
const core_1 = require("@looply/core");
|
|
11
|
+
const eas_cli_install_1 = require("./eas-cli-install");
|
|
12
|
+
const expo_release_1 = require("./expo-release");
|
|
13
|
+
const feature_settings_cache_1 = require("./feature-settings-cache");
|
|
14
|
+
const machine_secrets_1 = require("./machine-secrets");
|
|
15
|
+
const visual_proof_browser_1 = require("./visual-proof-browser");
|
|
16
|
+
const visual_proof_detect_1 = require("./visual-proof-detect");
|
|
17
|
+
/**
|
|
18
|
+
* WHAT THIS MACHINE SEES OF THE OPTIONAL FEATURES, FOR AUTORYN'S SWITCHES.
|
|
19
|
+
*
|
|
20
|
+
* AutoRyn shows real choices and a live status instead of asking the owner to
|
|
21
|
+
* type paths: the web apps found in the repository (with their build, folder
|
|
22
|
+
* and screens), the seed/fixture files a sign-in may be read from, which
|
|
23
|
+
* setting is in force for each feature (the repository's config.yaml wins), the
|
|
24
|
+
* EAS command line, and whether an Expo token is here (never the token).
|
|
25
|
+
*
|
|
26
|
+
* Reading the repository is bounded but not free, and one machine serves many
|
|
27
|
+
* repositories: the report is rebuilt at most every 30 minutes, or at once
|
|
28
|
+
* when the remote switches changed, and sent only when it changed.
|
|
29
|
+
*/
|
|
30
|
+
const REBUILD_MS = 30 * 60_000;
|
|
31
|
+
/** An Expo app in this repository (so its EAS command line is installed before the first release). */
|
|
32
|
+
function isExpoProject(projectDir) {
|
|
33
|
+
try {
|
|
34
|
+
const pkg = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(projectDir, 'package.json'), 'utf8'));
|
|
35
|
+
const dep = (n) => !!(pkg['dependencies']?.[n] ?? pkg['devDependencies']?.[n]);
|
|
36
|
+
return dep('expo') && ['app.json', 'app.config.js', 'app.config.ts'].some((f) => (0, node_fs_1.existsSync)((0, node_path_1.join)(projectDir, f)));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function expoTokenState(env = process.env, home) {
|
|
43
|
+
if (env['EXPO_TOKEN']?.trim())
|
|
44
|
+
return 'env';
|
|
45
|
+
if ((0, machine_secrets_1.readMachineSecret)('EXPO_TOKEN', home) === null)
|
|
46
|
+
return 'missing';
|
|
47
|
+
return (0, machine_secrets_1.isDelivered)('EXPO_TOKEN', home) ? 'delivered' : 'file';
|
|
48
|
+
}
|
|
49
|
+
function buildFeatureReport(input) {
|
|
50
|
+
const cache = (0, feature_settings_cache_1.readFeatureSettingsCache)(input.stateDir);
|
|
51
|
+
const remote = cache?.settings ?? null;
|
|
52
|
+
let inEffect = 'off';
|
|
53
|
+
let problem = null;
|
|
54
|
+
try {
|
|
55
|
+
const r = (0, visual_proof_detect_1.resolveVisualProofConfig)(input.projectDir, remote);
|
|
56
|
+
inEffect = r.from;
|
|
57
|
+
problem = r.problem;
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
inEffect = 'config.yaml';
|
|
61
|
+
problem = `the repository's .looply/config.yaml visual_proof section is not valid: ${e.message}`;
|
|
62
|
+
}
|
|
63
|
+
const browser = (input.browser ?? (() => (0, visual_proof_browser_1.findBrowser)()))() !== null ? 'found' : 'missing';
|
|
64
|
+
if (problem === null && inEffect !== 'off' && browser === 'missing')
|
|
65
|
+
problem = 'no Chrome, Edge or Playwright Chromium was found on this machine';
|
|
66
|
+
const repro = (0, core_1.bugReproEnabled)(input.config.bugRepro?.enabled, remote);
|
|
67
|
+
return {
|
|
68
|
+
visualProof: { inEffect, apps: (0, visual_proof_detect_1.detectWebApps)(input.projectDir), fixtureFiles: (0, visual_proof_detect_1.listFixtureFiles)(input.projectDir), browser, problem },
|
|
69
|
+
preview: { command: input.config.preview?.command ? 'config.yaml' : remote?.previewCommand ? 'remote' : 'none' },
|
|
70
|
+
release: { command: input.config.deliver?.release ? 'config.yaml' : remote?.releaseCommand ? 'remote' : 'none' },
|
|
71
|
+
bugRepro: { enabled: repro.enabled, from: repro.from },
|
|
72
|
+
appRelease: { easCli: input.eas.state, easCliVersion: input.eas.version, easCliProblem: input.eas.problem, expoToken: expoTokenState() },
|
|
73
|
+
skipped: cache?.skipped ?? [],
|
|
74
|
+
cliVersion: input.cliVersion,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** Rebuild when due or when the switches changed; send only what changed. Never throws. */
|
|
78
|
+
function makeFeatureReporter(deps) {
|
|
79
|
+
let builtAt = 0;
|
|
80
|
+
let builtFor = null;
|
|
81
|
+
let sent = null;
|
|
82
|
+
let report = null;
|
|
83
|
+
return async () => {
|
|
84
|
+
const now = (deps.now ?? Date.now)();
|
|
85
|
+
const cache = (0, feature_settings_cache_1.readFeatureSettingsCache)(deps.stateDir);
|
|
86
|
+
const switches = JSON.stringify(cache?.settings ?? null);
|
|
87
|
+
try {
|
|
88
|
+
if (report === null || now - builtAt >= REBUILD_MS || switches !== builtFor || report.appRelease.easCli === 'installing') {
|
|
89
|
+
// An Expo repository gets its EAS command line ahead of its first release.
|
|
90
|
+
const eas = (0, eas_cli_install_1.ensureEasCli)({ log: deps.log, globalScript: () => (0, expo_release_1.globalEasCliScript)() }, isExpoProject(deps.projectDir));
|
|
91
|
+
report = buildFeatureReport({ projectDir: deps.projectDir, stateDir: deps.stateDir, config: deps.config, cliVersion: deps.cliVersion, eas });
|
|
92
|
+
builtAt = now;
|
|
93
|
+
builtFor = switches;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
deps.log(`features: could not read what this repository offers (${e.message})`);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const key = (0, node_crypto_1.createHash)('sha256').update(JSON.stringify(report)).digest('hex');
|
|
101
|
+
if (key === sent)
|
|
102
|
+
return;
|
|
103
|
+
try {
|
|
104
|
+
await deps.send(report);
|
|
105
|
+
sent = key;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
/* an older server (404) or offline: the next pass tries again */
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=feature-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-report.js","sourceRoot":"","sources":["../src/feature-report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type FeatureSettings } from '@looply/core';
|
|
2
|
+
/**
|
|
3
|
+
* THE PROJECT'S REMOTE FEATURE SWITCHES, AS THIS MACHINE LAST HEARD THEM.
|
|
4
|
+
*
|
|
5
|
+
* Set in AutoRyn per component (screenshots, a preview or release command, bug
|
|
6
|
+
* reproduction); pulled by the daemon every five minutes and written here. A
|
|
7
|
+
* failed pull keeps the last answer, so an offline machine does what it was
|
|
8
|
+
* last told.
|
|
9
|
+
*
|
|
10
|
+
* Read leniently: a feature this build does not know is skipped (and reported),
|
|
11
|
+
* never a reason to drop the ones it does.
|
|
12
|
+
*
|
|
13
|
+
* Precedence, per feature: the repository's own config.yaml section → this → the defaults.
|
|
14
|
+
*/
|
|
15
|
+
export declare const FEATURE_SETTINGS_FILE = "feature-settings.json";
|
|
16
|
+
export interface FeatureSettingsCache {
|
|
17
|
+
settings: FeatureSettings | null;
|
|
18
|
+
skipped: string[];
|
|
19
|
+
updatedAt: string | null;
|
|
20
|
+
fetchedAt: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function readFeatureSettingsCache(stateDir: string): FeatureSettingsCache | null;
|
|
23
|
+
/**
|
|
24
|
+
* The remote switches for a project directory (a checkout resolves to its
|
|
25
|
+
* repository's shared state), or null. Never throws.
|
|
26
|
+
*/
|
|
27
|
+
export declare function remoteFeaturesFor(projectDir: string): FeatureSettings | null;
|
|
28
|
+
/**
|
|
29
|
+
* One pull: ask the server, write the cache when the answer changed. Never
|
|
30
|
+
* throws. A server without the route (older looply-api) answers 404: quietly
|
|
31
|
+
* "no remote switches".
|
|
32
|
+
*/
|
|
33
|
+
export declare function makeFeatureSettingsPull(deps: {
|
|
34
|
+
fetch(): Promise<unknown>;
|
|
35
|
+
stateDir: string;
|
|
36
|
+
log(line: string): void;
|
|
37
|
+
now(): number;
|
|
38
|
+
}): () => Promise<'updated' | 'unchanged' | 'failed'>;
|
|
39
|
+
//# sourceMappingURL=feature-settings-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-settings-cache.d.ts","sourceRoot":"","sources":["../src/feature-settings-cache.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2B,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAI7E;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAE7D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI,CAqBtF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAM5E;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC5C,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,IAAI,MAAM,CAAC;CACf,GAAG,MAAM,OAAO,CAAC,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC,CAkDpD"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FEATURE_SETTINGS_FILE = void 0;
|
|
4
|
+
exports.readFeatureSettingsCache = readFeatureSettingsCache;
|
|
5
|
+
exports.remoteFeaturesFor = remoteFeaturesFor;
|
|
6
|
+
exports.makeFeatureSettingsPull = makeFeatureSettingsPull;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const core_1 = require("@looply/core");
|
|
10
|
+
const git_driver_1 = require("./git-driver");
|
|
11
|
+
const server_client_1 = require("./server-client");
|
|
12
|
+
/**
|
|
13
|
+
* THE PROJECT'S REMOTE FEATURE SWITCHES, AS THIS MACHINE LAST HEARD THEM.
|
|
14
|
+
*
|
|
15
|
+
* Set in AutoRyn per component (screenshots, a preview or release command, bug
|
|
16
|
+
* reproduction); pulled by the daemon every five minutes and written here. A
|
|
17
|
+
* failed pull keeps the last answer, so an offline machine does what it was
|
|
18
|
+
* last told.
|
|
19
|
+
*
|
|
20
|
+
* Read leniently: a feature this build does not know is skipped (and reported),
|
|
21
|
+
* never a reason to drop the ones it does.
|
|
22
|
+
*
|
|
23
|
+
* Precedence, per feature: the repository's own config.yaml section → this → the defaults.
|
|
24
|
+
*/
|
|
25
|
+
exports.FEATURE_SETTINGS_FILE = 'feature-settings.json';
|
|
26
|
+
function readFeatureSettingsCache(stateDir) {
|
|
27
|
+
try {
|
|
28
|
+
const raw = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(stateDir, exports.FEATURE_SETTINGS_FILE), 'utf8'));
|
|
29
|
+
let settings = null;
|
|
30
|
+
let skipped = [];
|
|
31
|
+
if (raw['settings'] !== null && raw['settings'] !== undefined) {
|
|
32
|
+
const v = (0, core_1.validateFeatureSettings)(raw['settings'], { lenient: true });
|
|
33
|
+
if (!v.ok)
|
|
34
|
+
return null;
|
|
35
|
+
settings = v.settings;
|
|
36
|
+
// What the pull skipped is kept as written: the cache holds only the features this build knows.
|
|
37
|
+
skipped = Array.isArray(raw['skipped']) ? raw['skipped'].filter((s) => typeof s === 'string') : v.skipped;
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
settings,
|
|
41
|
+
skipped,
|
|
42
|
+
updatedAt: typeof raw['updatedAt'] === 'string' ? raw['updatedAt'] : null,
|
|
43
|
+
fetchedAt: typeof raw['fetchedAt'] === 'string' ? raw['fetchedAt'] : '',
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The remote switches for a project directory (a checkout resolves to its
|
|
52
|
+
* repository's shared state), or null. Never throws.
|
|
53
|
+
*/
|
|
54
|
+
function remoteFeaturesFor(projectDir) {
|
|
55
|
+
try {
|
|
56
|
+
return readFeatureSettingsCache((0, git_driver_1.projectStateDir)(projectDir))?.settings ?? null;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* One pull: ask the server, write the cache when the answer changed. Never
|
|
64
|
+
* throws. A server without the route (older looply-api) answers 404: quietly
|
|
65
|
+
* "no remote switches".
|
|
66
|
+
*/
|
|
67
|
+
function makeFeatureSettingsPull(deps) {
|
|
68
|
+
let failureReported = false;
|
|
69
|
+
const reportOnce = (why) => {
|
|
70
|
+
if (failureReported)
|
|
71
|
+
return;
|
|
72
|
+
failureReported = true;
|
|
73
|
+
deps.log(`features: could not refresh the project's feature switches — ${why}`);
|
|
74
|
+
};
|
|
75
|
+
return async () => {
|
|
76
|
+
let body;
|
|
77
|
+
try {
|
|
78
|
+
body = await deps.fetch();
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
if (e instanceof server_client_1.ServerError && e.status === 404)
|
|
82
|
+
return 'failed';
|
|
83
|
+
if (!(e instanceof server_client_1.ServerError && (e.isOffline || e.isAuth)))
|
|
84
|
+
reportOnce(e.message);
|
|
85
|
+
return 'failed';
|
|
86
|
+
}
|
|
87
|
+
const b = body;
|
|
88
|
+
if (typeof b !== 'object' || b === null || !('settings' in b)) {
|
|
89
|
+
reportOnce('the server answered with something that is not a settings envelope');
|
|
90
|
+
return 'failed';
|
|
91
|
+
}
|
|
92
|
+
let settings = null;
|
|
93
|
+
let skipped = [];
|
|
94
|
+
if (b.settings !== null) {
|
|
95
|
+
const v = (0, core_1.validateFeatureSettings)(b.settings, { lenient: true });
|
|
96
|
+
if (!v.ok) {
|
|
97
|
+
reportOnce(`the server sent a setting this build refuses (${v.key}: ${v.because})`);
|
|
98
|
+
return 'failed';
|
|
99
|
+
}
|
|
100
|
+
settings = v.settings;
|
|
101
|
+
skipped = v.skipped;
|
|
102
|
+
}
|
|
103
|
+
failureReported = false;
|
|
104
|
+
const updatedAt = typeof b.updatedAt === 'string' ? b.updatedAt : null;
|
|
105
|
+
const before = readFeatureSettingsCache(deps.stateDir);
|
|
106
|
+
if (before !== null && JSON.stringify(before.settings) === JSON.stringify(settings) && before.updatedAt === updatedAt)
|
|
107
|
+
return 'unchanged';
|
|
108
|
+
try {
|
|
109
|
+
(0, node_fs_1.mkdirSync)(deps.stateDir, { recursive: true });
|
|
110
|
+
const target = (0, node_path_1.join)(deps.stateDir, exports.FEATURE_SETTINGS_FILE);
|
|
111
|
+
const tmp = `${target}.${process.pid}.tmp`;
|
|
112
|
+
(0, node_fs_1.writeFileSync)(tmp, JSON.stringify({ settings, skipped, updatedAt, fetchedAt: new Date(deps.now()).toISOString() }, null, 2) + '\n', 'utf8');
|
|
113
|
+
(0, node_fs_1.renameSync)(tmp, target);
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
deps.log(`features: could not write the feature switch cache (${e.message})`);
|
|
117
|
+
return 'failed';
|
|
118
|
+
}
|
|
119
|
+
const on = settings === null ? 'defaults' : Object.keys(settings).join(', ') || 'defaults';
|
|
120
|
+
deps.log(`features: project feature switches are ${on}${skipped.length ? ` (this Looply does not know: ${skipped.join(', ')})` : ''}`);
|
|
121
|
+
return 'updated';
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=feature-settings-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-settings-cache.js","sourceRoot":"","sources":["../src/feature-settings-cache.ts"],"names":[],"mappings":";;;AA6BA,4DAqBC;AAMD,8CAMC;AAOD,0DAuDC;AA5HD,qCAA6E;AAC7E,yCAAiC;AACjC,uCAA6E;AAC7E,6CAA+C;AAC/C,mDAA8C;AAE9C;;;;;;;;;;;;GAYG;AAEU,QAAA,qBAAqB,GAAG,uBAAuB,CAAC;AAS7D,SAAgB,wBAAwB,CAAC,QAAgB;IACvD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,IAAA,gBAAI,EAAC,QAAQ,EAAE,6BAAqB,CAAC,EAAE,MAAM,CAAC,CAA4B,CAAC;QAC/G,IAAI,QAAQ,GAA2B,IAAI,CAAC;QAC5C,IAAI,OAAO,GAAa,EAAE,CAAC;QAC3B,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,SAAS,EAAE,CAAC;YAC9D,MAAM,CAAC,GAAG,IAAA,8BAAuB,EAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACtE,IAAI,CAAC,CAAC,CAAC,EAAE;gBAAE,OAAO,IAAI,CAAC;YACvB,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;YACtB,gGAAgG;YAChG,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QACzH,CAAC;QACD,OAAO;YACL,QAAQ;YACR,OAAO;YACP,SAAS,EAAE,OAAO,GAAG,CAAC,WAAW,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI;YACzE,SAAS,EAAE,OAAO,GAAG,CAAC,WAAW,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE;SACxE,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,UAAkB;IAClD,IAAI,CAAC;QACH,OAAO,wBAAwB,CAAC,IAAA,4BAAe,EAAC,UAAU,CAAC,CAAC,EAAE,QAAQ,IAAI,IAAI,CAAC;IACjF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAgB,uBAAuB,CAAC,IAKvC;IACC,IAAI,eAAe,GAAG,KAAK,CAAC;IAC5B,MAAM,UAAU,GAAG,CAAC,GAAW,EAAQ,EAAE;QACvC,IAAI,eAAe;YAAE,OAAO;QAC5B,eAAe,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,gEAAgE,GAAG,EAAE,CAAC,CAAC;IAClF,CAAC,CAAC;IACF,OAAO,KAAK,IAAI,EAAE;QAChB,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QAC5B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,YAAY,2BAAW,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,QAAQ,CAAC;YAClE,IAAI,CAAC,CAAC,CAAC,YAAY,2BAAW,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;gBAAE,UAAU,CAAE,CAAW,CAAC,OAAO,CAAC,CAAC;YAC/F,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,MAAM,CAAC,GAAG,IAA0D,CAAC;QACrE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,EAAE,CAAC;YAC9D,UAAU,CAAC,oEAAoE,CAAC,CAAC;YACjF,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,IAAI,QAAQ,GAA2B,IAAI,CAAC;QAC5C,IAAI,OAAO,GAAa,EAAE,CAAC;QAC3B,IAAI,CAAC,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YACxB,MAAM,CAAC,GAAG,IAAA,8BAAuB,EAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACjE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;gBACV,UAAU,CAAC,iDAAiD,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC;gBACpF,OAAO,QAAQ,CAAC;YAClB,CAAC;YACD,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;YACtB,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;QACtB,CAAC;QACD,eAAe,GAAG,KAAK,CAAC;QACxB,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;QACvE,MAAM,MAAM,GAAG,wBAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvD,IAAI,MAAM,KAAK,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS;YAAE,OAAO,WAAW,CAAC;QAC1I,IAAI,CAAC;YACH,IAAA,mBAAS,EAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9C,MAAM,MAAM,GAAG,IAAA,gBAAI,EAAC,IAAI,CAAC,QAAQ,EAAE,6BAAqB,CAAC,CAAC;YAC1D,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;YAC3C,IAAA,uBAAa,EAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;YAC5I,IAAA,oBAAU,EAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,GAAG,CAAC,uDAAwD,CAAW,CAAC,OAAO,GAAG,CAAC,CAAC;YACzF,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,MAAM,EAAE,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC;QAC3F,IAAI,CAAC,GAAG,CAAC,0CAA0C,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,gCAAgC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACvI,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SECRETS AN OWNER SET IN AUTORYN, OPENED ON THIS MACHINE ONLY.
|
|
3
|
+
*
|
|
4
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
* The machine keeps an RSA key pair in `~/.looply/keys/` (the user's own profile:
|
|
6
|
+
* no sandbox identity can read it) and gives looply-api the public half. AutoRyn
|
|
7
|
+
* seals a secret (the Expo token) to that key; looply-api relays the sealed text.
|
|
8
|
+
* Every five minutes the daemon fetches what is sealed to this machine, opens
|
|
9
|
+
* it, and writes the value to `~/.looply/secrets/<name>` — the file the Expo
|
|
10
|
+
* release already reads (`expo-token`) — then confirms the fingerprint it holds.
|
|
11
|
+
*
|
|
12
|
+
* 🔴 A VALUE IS NEVER LOGGED, NEVER REPORTED, NEVER PUT IN AN ERROR. What leaves
|
|
13
|
+
* this machine is the name, the fingerprint (a SHA-256 prefix) or a sentence
|
|
14
|
+
* saying why it could not be opened.
|
|
15
|
+
*
|
|
16
|
+
* A file a person put there by hand is never overwritten or removed: Looply only
|
|
17
|
+
* replaces or deletes a file whose fingerprint is the one it delivered itself.
|
|
18
|
+
*/
|
|
19
|
+
export declare const DELIVERED_FILE = ".delivered.json";
|
|
20
|
+
export declare function looplyHome(home?: string): string;
|
|
21
|
+
export declare function secretsDir(home?: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* This machine's seal key, made once. Many daemons start at once on a machine
|
|
24
|
+
* that serves many repositories, so the private key is published with a hard
|
|
25
|
+
* link — which fails if another daemon got there first — and the loser reads
|
|
26
|
+
* the winner's.
|
|
27
|
+
*/
|
|
28
|
+
export declare function ensureSealKey(home?: string): {
|
|
29
|
+
publicKey: string;
|
|
30
|
+
privateKey: string;
|
|
31
|
+
};
|
|
32
|
+
/** A secret's value on this machine (the file under `~/.looply/secrets`), or null. Never logged. */
|
|
33
|
+
export declare function readMachineSecret(name: string, home?: string): string | null;
|
|
34
|
+
/** Whether the file for `name` is the one Looply delivered (rather than one a person put there). */
|
|
35
|
+
export declare function isDelivered(name: string, home?: string): boolean;
|
|
36
|
+
export interface SecretsClient {
|
|
37
|
+
putSealKey(publicKey: string): Promise<unknown>;
|
|
38
|
+
machineSecrets(): Promise<{
|
|
39
|
+
secrets: Array<{
|
|
40
|
+
name: string;
|
|
41
|
+
sealed: string | null;
|
|
42
|
+
fingerprint: string | null;
|
|
43
|
+
removed: boolean;
|
|
44
|
+
}>;
|
|
45
|
+
}>;
|
|
46
|
+
ackMachineSecret(name: string, body: {
|
|
47
|
+
fingerprint: string | null;
|
|
48
|
+
problem: string | null;
|
|
49
|
+
}): Promise<unknown>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* One pass: make sure the server has the public key, then fetch, open, write and
|
|
53
|
+
* confirm. Never throws; an offline server is the next pass's problem.
|
|
54
|
+
*/
|
|
55
|
+
export declare function makeMachineSecretsPull(deps: {
|
|
56
|
+
client: SecretsClient;
|
|
57
|
+
log(line: string): void;
|
|
58
|
+
home?: string;
|
|
59
|
+
}): () => Promise<void>;
|
|
60
|
+
/** Environment for a remote command: each named secret's value, or the names that are missing. */
|
|
61
|
+
export declare function secretEnv(names: readonly string[] | undefined, home?: string): {
|
|
62
|
+
env: Record<string, string>;
|
|
63
|
+
missing: string[];
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=machine-secrets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine-secrets.d.ts","sourceRoot":"","sources":["../src/machine-secrets.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAEhD,wBAAgB,UAAU,CAAC,IAAI,GAAE,MAAkB,GAAG,MAAM,CAE3D;AAED,wBAAgB,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhD;AAMD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CA0BtF;AA6BD,oGAAoG;AACpG,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG5E;AAED,oGAAoG;AACpG,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAIhE;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChD,cAAc,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,OAAO,EAAE,OAAO,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IACrI,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAChH;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CA0FnI;AAED,kGAAkG;AAClG,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CASjI"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DELIVERED_FILE = void 0;
|
|
4
|
+
exports.looplyHome = looplyHome;
|
|
5
|
+
exports.secretsDir = secretsDir;
|
|
6
|
+
exports.ensureSealKey = ensureSealKey;
|
|
7
|
+
exports.readMachineSecret = readMachineSecret;
|
|
8
|
+
exports.isDelivered = isDelivered;
|
|
9
|
+
exports.makeMachineSecretsPull = makeMachineSecretsPull;
|
|
10
|
+
exports.secretEnv = secretEnv;
|
|
11
|
+
const node_crypto_1 = require("node:crypto");
|
|
12
|
+
const node_fs_1 = require("node:fs");
|
|
13
|
+
const node_os_1 = require("node:os");
|
|
14
|
+
const node_path_1 = require("node:path");
|
|
15
|
+
const core_1 = require("@looply/core");
|
|
16
|
+
const server_client_1 = require("./server-client");
|
|
17
|
+
/**
|
|
18
|
+
* SECRETS AN OWNER SET IN AUTORYN, OPENED ON THIS MACHINE ONLY.
|
|
19
|
+
*
|
|
20
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
21
|
+
* The machine keeps an RSA key pair in `~/.looply/keys/` (the user's own profile:
|
|
22
|
+
* no sandbox identity can read it) and gives looply-api the public half. AutoRyn
|
|
23
|
+
* seals a secret (the Expo token) to that key; looply-api relays the sealed text.
|
|
24
|
+
* Every five minutes the daemon fetches what is sealed to this machine, opens
|
|
25
|
+
* it, and writes the value to `~/.looply/secrets/<name>` — the file the Expo
|
|
26
|
+
* release already reads (`expo-token`) — then confirms the fingerprint it holds.
|
|
27
|
+
*
|
|
28
|
+
* 🔴 A VALUE IS NEVER LOGGED, NEVER REPORTED, NEVER PUT IN AN ERROR. What leaves
|
|
29
|
+
* this machine is the name, the fingerprint (a SHA-256 prefix) or a sentence
|
|
30
|
+
* saying why it could not be opened.
|
|
31
|
+
*
|
|
32
|
+
* A file a person put there by hand is never overwritten or removed: Looply only
|
|
33
|
+
* replaces or deletes a file whose fingerprint is the one it delivered itself.
|
|
34
|
+
*/
|
|
35
|
+
exports.DELIVERED_FILE = '.delivered.json';
|
|
36
|
+
function looplyHome(home = (0, node_os_1.homedir)()) {
|
|
37
|
+
return (0, node_path_1.join)(home, '.looply');
|
|
38
|
+
}
|
|
39
|
+
function secretsDir(home) {
|
|
40
|
+
return (0, node_path_1.join)(looplyHome(home), 'secrets');
|
|
41
|
+
}
|
|
42
|
+
function keysDir(home) {
|
|
43
|
+
return (0, node_path_1.join)(looplyHome(home), 'keys');
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* This machine's seal key, made once. Many daemons start at once on a machine
|
|
47
|
+
* that serves many repositories, so the private key is published with a hard
|
|
48
|
+
* link — which fails if another daemon got there first — and the loser reads
|
|
49
|
+
* the winner's.
|
|
50
|
+
*/
|
|
51
|
+
function ensureSealKey(home) {
|
|
52
|
+
const dir = keysDir(home);
|
|
53
|
+
const priv = (0, node_path_1.join)(dir, 'seal.pem');
|
|
54
|
+
const pub = (0, node_path_1.join)(dir, 'seal.pub.pem');
|
|
55
|
+
if ((0, node_fs_1.existsSync)(priv) && (0, node_fs_1.existsSync)(pub))
|
|
56
|
+
return { publicKey: (0, node_fs_1.readFileSync)(pub, 'utf8'), privateKey: (0, node_fs_1.readFileSync)(priv, 'utf8') };
|
|
57
|
+
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
58
|
+
const { publicKey, privateKey } = (0, node_crypto_1.generateKeyPairSync)('rsa', {
|
|
59
|
+
modulusLength: 3072,
|
|
60
|
+
publicKeyEncoding: { type: 'spki', format: 'pem' },
|
|
61
|
+
privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
|
|
62
|
+
});
|
|
63
|
+
const tmpPriv = `${priv}.${process.pid}.tmp`;
|
|
64
|
+
const tmpPub = `${pub}.${process.pid}.tmp`;
|
|
65
|
+
(0, node_fs_1.writeFileSync)(tmpPub, publicKey, { encoding: 'utf8', mode: 0o600 });
|
|
66
|
+
(0, node_fs_1.writeFileSync)(tmpPriv, privateKey, { encoding: 'utf8', mode: 0o600 });
|
|
67
|
+
try {
|
|
68
|
+
// The public half first: a reader that sees the private key always finds its public half.
|
|
69
|
+
if (!(0, node_fs_1.existsSync)(pub))
|
|
70
|
+
(0, node_fs_1.renameSync)(tmpPub, pub);
|
|
71
|
+
(0, node_fs_1.linkSync)(tmpPriv, priv);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
/* another daemon published first: theirs is the key */
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
(0, node_fs_1.rmSync)(tmpPriv, { force: true });
|
|
78
|
+
(0, node_fs_1.rmSync)(tmpPub, { force: true });
|
|
79
|
+
}
|
|
80
|
+
return { publicKey: (0, node_fs_1.readFileSync)(pub, 'utf8'), privateKey: (0, node_fs_1.readFileSync)(priv, 'utf8') };
|
|
81
|
+
}
|
|
82
|
+
function readDelivered(home) {
|
|
83
|
+
try {
|
|
84
|
+
const v = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(secretsDir(home), exports.DELIVERED_FILE), 'utf8'));
|
|
85
|
+
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
86
|
+
return {};
|
|
87
|
+
return Object.fromEntries(Object.entries(v).filter((e) => typeof e[1] === 'string'));
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return {};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function writeAtomic(path, text) {
|
|
94
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
95
|
+
(0, node_fs_1.writeFileSync)(tmp, text, { encoding: 'utf8', mode: 0o600 });
|
|
96
|
+
(0, node_fs_1.renameSync)(tmp, path);
|
|
97
|
+
}
|
|
98
|
+
function readValue(file) {
|
|
99
|
+
try {
|
|
100
|
+
const t = (0, node_fs_1.readFileSync)(file, 'utf8').trim();
|
|
101
|
+
return t === '' ? null : t;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** A secret's value on this machine (the file under `~/.looply/secrets`), or null. Never logged. */
|
|
108
|
+
function readMachineSecret(name, home) {
|
|
109
|
+
if (!core_1.SECRET_NAME.test(name))
|
|
110
|
+
return null;
|
|
111
|
+
return readValue((0, node_path_1.join)(secretsDir(home), (0, core_1.secretFileName)(name)));
|
|
112
|
+
}
|
|
113
|
+
/** Whether the file for `name` is the one Looply delivered (rather than one a person put there). */
|
|
114
|
+
function isDelivered(name, home) {
|
|
115
|
+
const value = readMachineSecret(name, home);
|
|
116
|
+
const fp = readDelivered(home)[name];
|
|
117
|
+
return value !== null && fp !== undefined && (0, core_1.secretFingerprint)(value) === fp;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* One pass: make sure the server has the public key, then fetch, open, write and
|
|
121
|
+
* confirm. Never throws; an offline server is the next pass's problem.
|
|
122
|
+
*/
|
|
123
|
+
function makeMachineSecretsPull(deps) {
|
|
124
|
+
let keySent = null;
|
|
125
|
+
let quiet = false;
|
|
126
|
+
return async () => {
|
|
127
|
+
let key;
|
|
128
|
+
try {
|
|
129
|
+
key = ensureSealKey(deps.home);
|
|
130
|
+
}
|
|
131
|
+
catch (e) {
|
|
132
|
+
if (!quiet)
|
|
133
|
+
deps.log(`secrets : could not make this machine's seal key (${e.message})`);
|
|
134
|
+
quiet = true;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
let listed;
|
|
138
|
+
try {
|
|
139
|
+
if (keySent !== key.publicKey) {
|
|
140
|
+
await deps.client.putSealKey(key.publicKey);
|
|
141
|
+
keySent = key.publicKey;
|
|
142
|
+
}
|
|
143
|
+
listed = await deps.client.machineSecrets();
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
// An older looply-api (404), offline, or signed out: nothing to deliver now.
|
|
147
|
+
if (!(e instanceof server_client_1.ServerError) && !quiet)
|
|
148
|
+
deps.log(`secrets : could not fetch this machine's secrets (${e.message})`);
|
|
149
|
+
quiet = true;
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
quiet = false;
|
|
153
|
+
const dir = secretsDir(deps.home);
|
|
154
|
+
const delivered = readDelivered(deps.home);
|
|
155
|
+
let changed = false;
|
|
156
|
+
for (const s of listed.secrets ?? []) {
|
|
157
|
+
if (!core_1.SECRET_NAME.test(s.name))
|
|
158
|
+
continue;
|
|
159
|
+
const file = (0, node_path_1.join)(dir, (0, core_1.secretFileName)(s.name));
|
|
160
|
+
const ack = (body) => deps.client.ackMachineSecret(s.name, body).catch(() => undefined);
|
|
161
|
+
if (s.removed || s.sealed === null) {
|
|
162
|
+
// Only the copy Looply put there goes; a file a person placed by hand stays.
|
|
163
|
+
if (delivered[s.name] !== undefined) {
|
|
164
|
+
const value = readValue(file);
|
|
165
|
+
if (value !== null && (0, core_1.secretFingerprint)(value) === delivered[s.name]) {
|
|
166
|
+
try {
|
|
167
|
+
(0, node_fs_1.unlinkSync)(file);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
/* already gone */
|
|
171
|
+
}
|
|
172
|
+
deps.log(`secrets : removed ${s.name} (switched off in AutoRyn)`);
|
|
173
|
+
}
|
|
174
|
+
delete delivered[s.name];
|
|
175
|
+
changed = true;
|
|
176
|
+
}
|
|
177
|
+
await ack({ fingerprint: null, problem: null });
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (delivered[s.name] === s.fingerprint && readValue(file) !== null)
|
|
181
|
+
continue;
|
|
182
|
+
const existing = readValue(file);
|
|
183
|
+
if (existing !== null && delivered[s.name] === undefined && (0, core_1.secretFingerprint)(existing) !== s.fingerprint) {
|
|
184
|
+
// A person's own file wins, as config.yaml wins over AutoRyn.
|
|
185
|
+
await ack({ fingerprint: null, problem: `this machine already has its own ${(0, core_1.secretFileName)(s.name)} file, which Looply leaves as it is; remove it on the PC to use the one set in AutoRyn` });
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
let value;
|
|
189
|
+
try {
|
|
190
|
+
value = (0, core_1.openSealed)(key.privateKey, s.sealed);
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
await ack({ fingerprint: null, problem: 'this machine could not open it (sealed to another key); send it again' });
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if ((0, core_1.secretFingerprint)(value) !== s.fingerprint) {
|
|
197
|
+
await ack({ fingerprint: null, problem: 'it did not match its fingerprint; send it again' });
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
202
|
+
writeAtomic(file, value);
|
|
203
|
+
}
|
|
204
|
+
catch (e) {
|
|
205
|
+
await ack({ fingerprint: null, problem: `could not be written on this machine (${e.message.replace(value, '[redacted]')})` });
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
delivered[s.name] = s.fingerprint ?? (0, core_1.secretFingerprint)(value);
|
|
209
|
+
changed = true;
|
|
210
|
+
deps.log(`secrets : ${s.name} received from AutoRyn`);
|
|
211
|
+
await ack({ fingerprint: delivered[s.name], problem: null });
|
|
212
|
+
}
|
|
213
|
+
if (changed) {
|
|
214
|
+
try {
|
|
215
|
+
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
216
|
+
writeAtomic((0, node_path_1.join)(dir, exports.DELIVERED_FILE), JSON.stringify(delivered, null, 2) + '\n');
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
/* the next pass writes it */
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/** Environment for a remote command: each named secret's value, or the names that are missing. */
|
|
225
|
+
function secretEnv(names, home) {
|
|
226
|
+
const env = {};
|
|
227
|
+
const missing = [];
|
|
228
|
+
for (const n of names ?? []) {
|
|
229
|
+
const v = process.env[n]?.trim() || readMachineSecret(n, home);
|
|
230
|
+
if (v)
|
|
231
|
+
env[n] = v;
|
|
232
|
+
else
|
|
233
|
+
missing.push(n);
|
|
234
|
+
}
|
|
235
|
+
return { env, missing };
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=machine-secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine-secrets.js","sourceRoot":"","sources":["../src/machine-secrets.ts"],"names":[],"mappings":"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"}
|
package/dist/preview-wiring.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ export interface PreviewWiringOpts {
|
|
|
29
29
|
} | null>;
|
|
30
30
|
heroku?: () => HerokuApi | null;
|
|
31
31
|
runCommand?: PreviewCommandRunner;
|
|
32
|
+
/** Tests: the sandboxed runner a command set in AutoRyn goes through. */
|
|
33
|
+
runContained?: PreviewCommandRunner;
|
|
32
34
|
now?: () => number;
|
|
33
35
|
}
|
|
34
36
|
export declare function makePreviewAdvancer(opts: PreviewWiringOpts): PreviewAdvancer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview-wiring.d.ts","sourceRoot":"","sources":["../src/preview-wiring.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAA8B,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EAA8B,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EASL,KAAK,oBAAoB,EAC1B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAA2B,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"preview-wiring.d.ts","sourceRoot":"","sources":["../src/preview-wiring.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAA8B,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EAA8B,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EASL,KAAK,oBAAoB,EAC1B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAA2B,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAIrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IACtC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,eAAe,GAAG,wBAAwB,CAAC,CAAC;IACvE,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,GAAG,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,mBAAmB,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAC1G,MAAM,CAAC,EAAE,MAAM,SAAS,GAAG,IAAI,CAAC;IAChC,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,yEAAyE;IACzE,YAAY,CAAC,EAAE,oBAAoB,CAAC;IACpC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,eAAe,CAmF5E"}
|