@wenrwa/marketplace-cli 0.8.9 → 0.8.10
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.
|
@@ -215,6 +215,22 @@ describe('PreviewRunner (tp-05) — real git, real processes', () => {
|
|
|
215
215
|
expect(await runner.update({ workspaceId: 'ws-1', repoUrl: fx.remote })).toMatchObject({ status: 'running', runningSha: fixed });
|
|
216
216
|
expect(JSON.parse(await get(port)).message).toBe('v3 fixed');
|
|
217
217
|
});
|
|
218
|
+
it('tp-17: the log reply never carries a .env value, even one printed bare by the app', async () => {
|
|
219
|
+
// A value no token pattern recognises, logged on its own line by merged app code.
|
|
220
|
+
fs.appendFileSync(path.join(fx.workingCopy, '.env'), 'PLAIN_SECRET=plainvalue9f3a2b7c41\nSHORT=on\n');
|
|
221
|
+
pushChange(fx, {
|
|
222
|
+
'server.js': `console.log(process.env.PLAIN_SECRET); console.log('using ' + process.env.OWNER_SECRET + ' and ' + process.env.SHORT);\n${SERVER_JS}`,
|
|
223
|
+
}, 'logs a key');
|
|
224
|
+
const r = await runner.start({ workspaceId: 'ws-1', repoUrl: fx.remote });
|
|
225
|
+
expect(r.status).toBe('running');
|
|
226
|
+
await new Promise((res) => setTimeout(res, 300));
|
|
227
|
+
const { log } = runner.logs({ workspaceId: 'ws-1' });
|
|
228
|
+
expect(log).toContain('using ');
|
|
229
|
+
expect(log).not.toContain('plainvalue9f3a2b7c41');
|
|
230
|
+
expect(log).not.toContain('sk_live_owner_value');
|
|
231
|
+
// Short values (flags, ports) stay readable: masking them would blank the log.
|
|
232
|
+
expect(log).toContain(' and on');
|
|
233
|
+
});
|
|
218
234
|
it('pins to the remote default branch — another branch pushed to the remote never runs', async () => {
|
|
219
235
|
git(fx.author, 'checkout', '-b', 'feature');
|
|
220
236
|
fs.writeFileSync(path.join(fx.author, 'message.txt'), 'feature branch\n');
|
|
@@ -61,6 +61,18 @@ export interface PreviewRunnerOpts {
|
|
|
61
61
|
/** The only address a preview app may listen on. */
|
|
62
62
|
export declare const PREVIEW_BIND_HOST = "127.0.0.1";
|
|
63
63
|
export declare const PREVIEW_PASSTHROUGH_ENV: readonly ["PATH", "HOME", "USER", "LANG", "LC_ALL", "TZ", "TMPDIR", "SHELL"];
|
|
64
|
+
/**
|
|
65
|
+
* tp-17 — `.env` values this long or longer are masked in the log reply by
|
|
66
|
+
* VALUE, whatever their shape. Shorter ones (ports, flags, `production`) stay:
|
|
67
|
+
* masking them would blank half the log and they are not secrets.
|
|
68
|
+
*/
|
|
69
|
+
export declare const LOG_MASK_MIN_VALUE_LENGTH = 8;
|
|
70
|
+
/**
|
|
71
|
+
* tp-17 — mask every given value in `text`, longest first (so a value that
|
|
72
|
+
* contains another is masked whole). Pattern redaction (`redact`) misses a key
|
|
73
|
+
* the app prints bare with no recognisable shape; this never does.
|
|
74
|
+
*/
|
|
75
|
+
export declare function maskEnvValues(text: string, values: Iterable<string>): string;
|
|
64
76
|
/**
|
|
65
77
|
* The preview env: allowlisted process names < the owner's repo `.env`
|
|
66
78
|
* (reserved names already removed by loadRepoEnv) < the fixed PORT.
|
|
@@ -85,6 +97,8 @@ export declare function installCommand(files: (name: string) => boolean): [strin
|
|
|
85
97
|
export declare class PreviewRunner {
|
|
86
98
|
private readonly opts;
|
|
87
99
|
private readonly states;
|
|
100
|
+
/** tp-17 — the `.env` values each workspace's last deploy ran with (log masking). */
|
|
101
|
+
private readonly deployedEnvValues;
|
|
88
102
|
/** One port, so one operation at a time across the whole box. */
|
|
89
103
|
private chain;
|
|
90
104
|
private orphanSwept;
|
|
@@ -33,7 +33,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.PreviewRunner = exports.PREVIEW_PASSTHROUGH_ENV = exports.PREVIEW_BIND_HOST = void 0;
|
|
36
|
+
exports.PreviewRunner = exports.LOG_MASK_MIN_VALUE_LENGTH = exports.PREVIEW_PASSTHROUGH_ENV = exports.PREVIEW_BIND_HOST = void 0;
|
|
37
|
+
exports.maskEnvValues = maskEnvValues;
|
|
37
38
|
exports.buildPreviewEnv = buildPreviewEnv;
|
|
38
39
|
exports.loopbackArgs = loopbackArgs;
|
|
39
40
|
exports.machineExternalAddresses = machineExternalAddresses;
|
|
@@ -116,6 +117,24 @@ const redact_1 = require("../secrets/redact");
|
|
|
116
117
|
/** The only address a preview app may listen on. */
|
|
117
118
|
exports.PREVIEW_BIND_HOST = '127.0.0.1';
|
|
118
119
|
exports.PREVIEW_PASSTHROUGH_ENV = ['PATH', 'HOME', 'USER', 'LANG', 'LC_ALL', 'TZ', 'TMPDIR', 'SHELL'];
|
|
120
|
+
/**
|
|
121
|
+
* tp-17 — `.env` values this long or longer are masked in the log reply by
|
|
122
|
+
* VALUE, whatever their shape. Shorter ones (ports, flags, `production`) stay:
|
|
123
|
+
* masking them would blank half the log and they are not secrets.
|
|
124
|
+
*/
|
|
125
|
+
exports.LOG_MASK_MIN_VALUE_LENGTH = 8;
|
|
126
|
+
/**
|
|
127
|
+
* tp-17 — mask every given value in `text`, longest first (so a value that
|
|
128
|
+
* contains another is masked whole). Pattern redaction (`redact`) misses a key
|
|
129
|
+
* the app prints bare with no recognisable shape; this never does.
|
|
130
|
+
*/
|
|
131
|
+
function maskEnvValues(text, values) {
|
|
132
|
+
const list = [...new Set([...values].filter((v) => v.length >= exports.LOG_MASK_MIN_VALUE_LENGTH))].sort((a, b) => b.length - a.length);
|
|
133
|
+
let out = text;
|
|
134
|
+
for (const v of list)
|
|
135
|
+
out = out.split(v).join('*'.repeat(v.length));
|
|
136
|
+
return out;
|
|
137
|
+
}
|
|
119
138
|
const DEFAULT_READY_TIMEOUT = { built: 120_000, dev: 300_000 };
|
|
120
139
|
const DEFAULT_STEP_TIMEOUT_MS = 15 * 60_000;
|
|
121
140
|
const LOG_TAIL_LINES = 200;
|
|
@@ -204,6 +223,8 @@ function runnerFor(files) {
|
|
|
204
223
|
class PreviewRunner {
|
|
205
224
|
opts;
|
|
206
225
|
states = new Map();
|
|
226
|
+
/** tp-17 — the `.env` values each workspace's last deploy ran with (log masking). */
|
|
227
|
+
deployedEnvValues = new Map();
|
|
207
228
|
/** One port, so one operation at a time across the whole box. */
|
|
208
229
|
chain = Promise.resolve();
|
|
209
230
|
orphanSwept = false;
|
|
@@ -280,7 +301,13 @@ class PreviewRunner {
|
|
|
280
301
|
out = out.slice(-LOG_TAIL_MAX_CHARS);
|
|
281
302
|
truncated = true;
|
|
282
303
|
}
|
|
283
|
-
|
|
304
|
+
// Pattern masking, then the owner's own .env values by value — the ones
|
|
305
|
+
// the last deploy ran with and the ones on disk now (an edited .env).
|
|
306
|
+
const values = [
|
|
307
|
+
...(this.deployedEnvValues.get(req.workspaceId) ?? []),
|
|
308
|
+
...Object.values((0, repoEnv_1.loadRepoEnv)(this.opts.workingCopyDir(req.workspaceId))),
|
|
309
|
+
];
|
|
310
|
+
return { log: maskEnvValues((0, redact_1.redact)(out), values), truncated };
|
|
284
311
|
}
|
|
285
312
|
status(workspaceId) {
|
|
286
313
|
return this.snapshot(workspaceId, {});
|
|
@@ -424,7 +451,9 @@ class PreviewRunner {
|
|
|
424
451
|
message: `No "${runScript}" script in package.json.`,
|
|
425
452
|
});
|
|
426
453
|
}
|
|
427
|
-
const
|
|
454
|
+
const repoEnv = (0, repoEnv_1.loadRepoEnv)(this.opts.workingCopyDir(workspaceId));
|
|
455
|
+
this.deployedEnvValues.set(workspaceId, Object.values(repoEnv));
|
|
456
|
+
const env = buildPreviewEnv(this.opts.baseEnv, repoEnv, this.opts.port);
|
|
428
457
|
// 2. Install, then (built) build — beside whatever is serving.
|
|
429
458
|
const [installCmd, installArgs] = installCommand(has);
|
|
430
459
|
const installed = await this.runStep(installCmd, installArgs, slotDir, env, logFile);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wenrwa/marketplace-cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.10",
|
|
4
4
|
"description": "CLI tool for the Wenrwa Agent Marketplace — monitor bounties, agents, workspaces, and treasury from your terminal",
|
|
5
5
|
"author": "Wenrwa <dev@wenrwa.com>",
|
|
6
6
|
"license": "MIT",
|