@i4ctime/q-ring 0.13.0 → 0.14.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/README.md +9 -8
- package/assets/icon-192.png +0 -0
- package/assets/icon-512.png +0 -0
- package/assets/mark-mono.svg +27 -0
- package/assets/mark-small.svg +15 -0
- package/assets/mark.svg +44 -0
- package/assets/repo-social-preview.png +0 -0
- package/assets/social-card-optimized.jpg +0 -0
- package/dist/{chunk-SRESNRML.js → chunk-C2TFJ2EH.js} +466 -200
- package/dist/chunk-C2TFJ2EH.js.map +1 -0
- package/dist/{chunk-CWV3WTPF.js → chunk-NNIEXAW5.js} +454 -194
- package/dist/chunk-NNIEXAW5.js.map +1 -0
- package/dist/{dashboard-II2ILNXA.js → dashboard-KAUEPLXO.js} +2 -2
- package/dist/{dashboard-RLMROWIU.js → dashboard-PYYAED45.js} +2 -2
- package/dist/index.js +60 -8
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +49 -7
- package/dist/mcp.js.map +1 -1
- package/package.json +21 -8
- package/dist/chunk-CWV3WTPF.js.map +0 -1
- package/dist/chunk-SRESNRML.js.map +0 -1
- /package/dist/{dashboard-II2ILNXA.js.map → dashboard-KAUEPLXO.js.map} +0 -0
- /package/dist/{dashboard-RLMROWIU.js.map → dashboard-PYYAED45.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
checkSSRF,
|
|
7
7
|
clearMemory,
|
|
8
8
|
collapseEnvironment,
|
|
9
|
+
countLegacyApprovals,
|
|
9
10
|
deleteSecret,
|
|
10
11
|
detectAnomalies,
|
|
11
12
|
disableHook,
|
|
@@ -36,13 +37,14 @@ import {
|
|
|
36
37
|
remember,
|
|
37
38
|
removeHook,
|
|
38
39
|
revokeApproval,
|
|
40
|
+
serviceForScope,
|
|
39
41
|
setSecret,
|
|
40
42
|
tunnelCreate,
|
|
41
43
|
tunnelDestroy,
|
|
42
44
|
tunnelList,
|
|
43
45
|
tunnelRead,
|
|
44
46
|
verifyAuditChain
|
|
45
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-C2TFJ2EH.js";
|
|
46
48
|
|
|
47
49
|
// src/cli/commands.ts
|
|
48
50
|
import { Command, Help } from "commander";
|
|
@@ -1881,12 +1883,39 @@ function registerValidationCommands(program2) {
|
|
|
1881
1883
|
|
|
1882
1884
|
// src/core/exec.ts
|
|
1883
1885
|
import { spawn } from "child_process";
|
|
1886
|
+
import { StringDecoder } from "string_decoder";
|
|
1884
1887
|
import { Transform } from "stream";
|
|
1885
1888
|
var BUILTIN_PROFILES = {
|
|
1886
1889
|
unrestricted: { name: "unrestricted" },
|
|
1887
1890
|
restricted: {
|
|
1888
1891
|
name: "restricted",
|
|
1889
|
-
denyCommands: [
|
|
1892
|
+
denyCommands: [
|
|
1893
|
+
// Network tools.
|
|
1894
|
+
"curl",
|
|
1895
|
+
"wget",
|
|
1896
|
+
"ssh",
|
|
1897
|
+
"scp",
|
|
1898
|
+
"nc",
|
|
1899
|
+
"netcat",
|
|
1900
|
+
"ncat",
|
|
1901
|
+
// Interpreters and shells: given the secret env vars, `python -c`,
|
|
1902
|
+
// `node -e`, `bash -c`, etc. can perform arbitrary network I/O and
|
|
1903
|
+
// exfiltrate them, defeating allowNetwork. Denied by default in
|
|
1904
|
+
// `restricted`; to run them with secrets use a custom profile in
|
|
1905
|
+
// .q-ring.json, or the `ci` / `unrestricted` profile.
|
|
1906
|
+
"python",
|
|
1907
|
+
"python2",
|
|
1908
|
+
"python3",
|
|
1909
|
+
"node",
|
|
1910
|
+
"deno",
|
|
1911
|
+
"bun",
|
|
1912
|
+
"perl",
|
|
1913
|
+
"ruby",
|
|
1914
|
+
"php",
|
|
1915
|
+
"sh",
|
|
1916
|
+
"bash",
|
|
1917
|
+
"zsh"
|
|
1918
|
+
],
|
|
1890
1919
|
maxRuntimeSeconds: 30,
|
|
1891
1920
|
allowNetwork: false,
|
|
1892
1921
|
stripEnvVars: ["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY"]
|
|
@@ -1906,6 +1935,11 @@ var RedactionTransform = class extends Transform {
|
|
|
1906
1935
|
patterns = [];
|
|
1907
1936
|
tail = "";
|
|
1908
1937
|
maxLen = 0;
|
|
1938
|
+
// Decodes UTF-8 across chunk boundaries: a multi-byte character split between
|
|
1939
|
+
// two Buffer chunks would otherwise be corrupted to U+FFFD by chunk.toString()
|
|
1940
|
+
// BEFORE matching runs, letting a multi-byte secret slip through unredacted.
|
|
1941
|
+
// StringDecoder buffers the incomplete trailing bytes until the rest arrives.
|
|
1942
|
+
decoder = new StringDecoder("utf8");
|
|
1909
1943
|
constructor(secretsToRedact) {
|
|
1910
1944
|
super();
|
|
1911
1945
|
const validSecrets = secretsToRedact.filter((s) => s.length > 5);
|
|
@@ -1923,7 +1957,8 @@ var RedactionTransform = class extends Transform {
|
|
|
1923
1957
|
this.push(chunk);
|
|
1924
1958
|
return callback();
|
|
1925
1959
|
}
|
|
1926
|
-
const
|
|
1960
|
+
const decoded = typeof chunk === "string" ? chunk : this.decoder.write(chunk);
|
|
1961
|
+
const text = this.tail + decoded;
|
|
1927
1962
|
let redacted = text;
|
|
1928
1963
|
for (const { value, replacement } of this.patterns) {
|
|
1929
1964
|
redacted = redacted.split(value).join(replacement);
|
|
@@ -1939,8 +1974,8 @@ var RedactionTransform = class extends Transform {
|
|
|
1939
1974
|
callback();
|
|
1940
1975
|
}
|
|
1941
1976
|
_flush(callback) {
|
|
1942
|
-
|
|
1943
|
-
|
|
1977
|
+
let final = this.tail + this.decoder.end();
|
|
1978
|
+
if (final) {
|
|
1944
1979
|
for (const { value, replacement } of this.patterns) {
|
|
1945
1980
|
final = final.split(value).join(replacement);
|
|
1946
1981
|
}
|
|
@@ -2457,7 +2492,7 @@ function registerToolingCommands(program2) {
|
|
|
2457
2492
|
}
|
|
2458
2493
|
});
|
|
2459
2494
|
program2.command("status").description("Launch the quantum status dashboard in your browser").option("--port <port>", "Port to serve on", "9876").option("--no-open", "Don't auto-open the browser").action(async (cmd) => {
|
|
2460
|
-
const { startDashboardServer } = await import("./dashboard-
|
|
2495
|
+
const { startDashboardServer } = await import("./dashboard-PYYAED45.js");
|
|
2461
2496
|
const { exec } = await import("child_process");
|
|
2462
2497
|
const { platform } = await import("os");
|
|
2463
2498
|
const port = Number(cmd.port);
|
|
@@ -3245,6 +3280,7 @@ function registerSecurityCommands(program2) {
|
|
|
3245
3280
|
).option("-g, --global", "Global scope").option("-p, --project", "Project scope").option("--project-path <path>", "Explicit project path").option("--for <seconds>", "Duration of approval in seconds", parseInt, 3600).option("--reason <text>", "Reason for granting approval").option("--revoke", "Revoke an existing approval").option("--list", "List all approvals").action((key, cmd) => {
|
|
3246
3281
|
const opts = buildOpts(cmd);
|
|
3247
3282
|
const scope = opts.scope ?? "global";
|
|
3283
|
+
const service = serviceForScope(scope, opts);
|
|
3248
3284
|
if (cmd.list) {
|
|
3249
3285
|
const approvals = listApprovals();
|
|
3250
3286
|
if (approvals.length === 0) {
|
|
@@ -3266,7 +3302,7 @@ function registerSecurityCommands(program2) {
|
|
|
3266
3302
|
return;
|
|
3267
3303
|
}
|
|
3268
3304
|
if (cmd.revoke) {
|
|
3269
|
-
const revoked = revokeApproval(key, scope);
|
|
3305
|
+
const revoked = revokeApproval(key, scope, service);
|
|
3270
3306
|
if (revoked) {
|
|
3271
3307
|
console.log(
|
|
3272
3308
|
`${SYMBOLS.check} ${c.yellow("revoked")} approval for ${c.bold(key)}`
|
|
@@ -3276,7 +3312,7 @@ function registerSecurityCommands(program2) {
|
|
|
3276
3312
|
}
|
|
3277
3313
|
return;
|
|
3278
3314
|
}
|
|
3279
|
-
const entry = grantApproval(key, scope, cmd.for, {
|
|
3315
|
+
const entry = grantApproval(key, scope, service, cmd.for, {
|
|
3280
3316
|
reason: cmd.reason ?? "manual approval"
|
|
3281
3317
|
});
|
|
3282
3318
|
console.log(
|
|
@@ -3482,6 +3518,21 @@ function checkPolicy() {
|
|
|
3482
3518
|
detail: active.length ? `active: ${active.join(", ")}` : 'none configured (add a "policy" section to .q-ring.json to enable)'
|
|
3483
3519
|
};
|
|
3484
3520
|
}
|
|
3521
|
+
function checkLegacyApprovals() {
|
|
3522
|
+
const n = countLegacyApprovals();
|
|
3523
|
+
if (n === 0) {
|
|
3524
|
+
return {
|
|
3525
|
+
name: "approval bindings",
|
|
3526
|
+
status: "ok",
|
|
3527
|
+
detail: "no legacy approvals; all bound to a project/team/org identity"
|
|
3528
|
+
};
|
|
3529
|
+
}
|
|
3530
|
+
return {
|
|
3531
|
+
name: "approval bindings",
|
|
3532
|
+
status: "warn",
|
|
3533
|
+
detail: `${n} pre-v0.14 approval(s) have no project binding and will NOT grant access \u2014 re-run \`qring approve\` for each`
|
|
3534
|
+
};
|
|
3535
|
+
}
|
|
3485
3536
|
function checkMcpBinary() {
|
|
3486
3537
|
const exts = process.platform === "win32" ? [".cmd", ".exe", ".bat", ""] : [""];
|
|
3487
3538
|
for (const dir of (process.env.PATH ?? "").split(delimiter)) {
|
|
@@ -3511,6 +3562,7 @@ function registerDoctorCommand(program2) {
|
|
|
3511
3562
|
checkAuditLog(),
|
|
3512
3563
|
checkManifest(projectPath),
|
|
3513
3564
|
checkPolicy(),
|
|
3565
|
+
checkLegacyApprovals(),
|
|
3514
3566
|
checkMcpBinary()
|
|
3515
3567
|
];
|
|
3516
3568
|
const failed = checks.filter((r) => r.status === "fail").length;
|