@i4ctime/q-ring 0.13.1 → 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 +1 -0
- 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-Z7UJFHVE.js → chunk-C2TFJ2EH.js} +440 -186
- package/dist/chunk-C2TFJ2EH.js.map +1 -0
- package/dist/{chunk-Q3UCKJAJ.js → chunk-NNIEXAW5.js} +428 -180
- package/dist/chunk-NNIEXAW5.js.map +1 -0
- package/dist/{dashboard-2UDYGGTT.js → dashboard-KAUEPLXO.js} +2 -2
- package/dist/{dashboard-2IGUR7PA.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 +18 -6
- package/dist/chunk-Q3UCKJAJ.js.map +0 -1
- package/dist/chunk-Z7UJFHVE.js.map +0 -1
- /package/dist/{dashboard-2IGUR7PA.js.map → dashboard-KAUEPLXO.js.map} +0 -0
- /package/dist/{dashboard-2UDYGGTT.js.map → dashboard-PYYAED45.js.map} +0 -0
package/dist/mcp.js
CHANGED
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
tunnelList,
|
|
40
40
|
tunnelRead,
|
|
41
41
|
verifyAuditChain
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-NNIEXAW5.js";
|
|
43
43
|
|
|
44
44
|
// src/mcp.ts
|
|
45
45
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -710,6 +710,15 @@ function registerSecretTools(server2) {
|
|
|
710
710
|
params.sourceProjectPath
|
|
711
711
|
);
|
|
712
712
|
if (toolBlock) return toolBlock;
|
|
713
|
+
for (const key of [params.sourceKey, params.targetKey]) {
|
|
714
|
+
const decision = checkKeyReadPolicy(key, void 0, params.sourceProjectPath);
|
|
715
|
+
if (!decision.allowed) {
|
|
716
|
+
return text(
|
|
717
|
+
`Policy Denied: ${decision.reason} (source: ${decision.policySource})`,
|
|
718
|
+
true
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
713
722
|
entangleSecrets(
|
|
714
723
|
params.sourceKey,
|
|
715
724
|
{
|
|
@@ -2038,12 +2047,39 @@ function runHealthScan(config = {}) {
|
|
|
2038
2047
|
|
|
2039
2048
|
// src/core/exec.ts
|
|
2040
2049
|
import { spawn } from "child_process";
|
|
2050
|
+
import { StringDecoder } from "string_decoder";
|
|
2041
2051
|
import { Transform } from "stream";
|
|
2042
2052
|
var BUILTIN_PROFILES = {
|
|
2043
2053
|
unrestricted: { name: "unrestricted" },
|
|
2044
2054
|
restricted: {
|
|
2045
2055
|
name: "restricted",
|
|
2046
|
-
denyCommands: [
|
|
2056
|
+
denyCommands: [
|
|
2057
|
+
// Network tools.
|
|
2058
|
+
"curl",
|
|
2059
|
+
"wget",
|
|
2060
|
+
"ssh",
|
|
2061
|
+
"scp",
|
|
2062
|
+
"nc",
|
|
2063
|
+
"netcat",
|
|
2064
|
+
"ncat",
|
|
2065
|
+
// Interpreters and shells: given the secret env vars, `python -c`,
|
|
2066
|
+
// `node -e`, `bash -c`, etc. can perform arbitrary network I/O and
|
|
2067
|
+
// exfiltrate them, defeating allowNetwork. Denied by default in
|
|
2068
|
+
// `restricted`; to run them with secrets use a custom profile in
|
|
2069
|
+
// .q-ring.json, or the `ci` / `unrestricted` profile.
|
|
2070
|
+
"python",
|
|
2071
|
+
"python2",
|
|
2072
|
+
"python3",
|
|
2073
|
+
"node",
|
|
2074
|
+
"deno",
|
|
2075
|
+
"bun",
|
|
2076
|
+
"perl",
|
|
2077
|
+
"ruby",
|
|
2078
|
+
"php",
|
|
2079
|
+
"sh",
|
|
2080
|
+
"bash",
|
|
2081
|
+
"zsh"
|
|
2082
|
+
],
|
|
2047
2083
|
maxRuntimeSeconds: 30,
|
|
2048
2084
|
allowNetwork: false,
|
|
2049
2085
|
stripEnvVars: ["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY"]
|
|
@@ -2063,6 +2099,11 @@ var RedactionTransform = class extends Transform {
|
|
|
2063
2099
|
patterns = [];
|
|
2064
2100
|
tail = "";
|
|
2065
2101
|
maxLen = 0;
|
|
2102
|
+
// Decodes UTF-8 across chunk boundaries: a multi-byte character split between
|
|
2103
|
+
// two Buffer chunks would otherwise be corrupted to U+FFFD by chunk.toString()
|
|
2104
|
+
// BEFORE matching runs, letting a multi-byte secret slip through unredacted.
|
|
2105
|
+
// StringDecoder buffers the incomplete trailing bytes until the rest arrives.
|
|
2106
|
+
decoder = new StringDecoder("utf8");
|
|
2066
2107
|
constructor(secretsToRedact) {
|
|
2067
2108
|
super();
|
|
2068
2109
|
const validSecrets = secretsToRedact.filter((s) => s.length > 5);
|
|
@@ -2080,7 +2121,8 @@ var RedactionTransform = class extends Transform {
|
|
|
2080
2121
|
this.push(chunk);
|
|
2081
2122
|
return callback();
|
|
2082
2123
|
}
|
|
2083
|
-
const
|
|
2124
|
+
const decoded = typeof chunk === "string" ? chunk : this.decoder.write(chunk);
|
|
2125
|
+
const text2 = this.tail + decoded;
|
|
2084
2126
|
let redacted = text2;
|
|
2085
2127
|
for (const { value, replacement } of this.patterns) {
|
|
2086
2128
|
redacted = redacted.split(value).join(replacement);
|
|
@@ -2096,8 +2138,8 @@ var RedactionTransform = class extends Transform {
|
|
|
2096
2138
|
callback();
|
|
2097
2139
|
}
|
|
2098
2140
|
_flush(callback) {
|
|
2099
|
-
|
|
2100
|
-
|
|
2141
|
+
let final = this.tail + this.decoder.end();
|
|
2142
|
+
if (final) {
|
|
2101
2143
|
for (const { value, replacement } of this.patterns) {
|
|
2102
2144
|
final = final.split(value).join(replacement);
|
|
2103
2145
|
}
|
|
@@ -2491,7 +2533,7 @@ function registerToolingTools(server2) {
|
|
|
2491
2533
|
"Inject only secrets carrying at least one of these tags. Combinable with `keys` as an AND filter."
|
|
2492
2534
|
),
|
|
2493
2535
|
profile: z9.enum(["unrestricted", "restricted", "ci"]).optional().default("restricted").describe(
|
|
2494
|
-
"Exec sandbox profile. 'restricted' (default) denies
|
|
2536
|
+
"Exec sandbox profile. 'restricted' (default) denies network-tool binaries (curl, wget, ssh, scp, nc, netcat, ncat) AND common interpreters/shells (python, node, deno, bun, perl, ruby, php, sh, bash, zsh) \u2014 since those could otherwise egress the injected secrets \u2014 strips proxy env vars, and caps runtime at 30s. It still is NOT a real OS sandbox (it does not restrict PATH, and some allowed binary could in principle make network calls); for genuinely untrusted commands use OS-level isolation (containers, network namespaces). 'ci' allows network and interpreters with a 300s cap and blocks a few destructive commands; 'unrestricted' inherits the full server environment. Define a custom profile in .q-ring.json to allow specific interpreters with secrets."
|
|
2495
2537
|
),
|
|
2496
2538
|
scope: scope6,
|
|
2497
2539
|
projectPath: projectPath6,
|
|
@@ -2658,7 +2700,7 @@ ${result.stderr}`);
|
|
|
2658
2700
|
`Dashboard already running at ${dashboardInstance.url}`
|
|
2659
2701
|
);
|
|
2660
2702
|
}
|
|
2661
|
-
const { startDashboardServer } = await import("./dashboard-
|
|
2703
|
+
const { startDashboardServer } = await import("./dashboard-KAUEPLXO.js");
|
|
2662
2704
|
dashboardInstance = startDashboardServer({ port: params.port });
|
|
2663
2705
|
return text(
|
|
2664
2706
|
`Dashboard started at ${dashboardInstance.url}
|