@volter/teams 0.2.19 → 0.2.20
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/package.json +1 -1
- package/redact.mjs +10 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/teams",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Volter Teams, the neutral team plane: machine identity and daemon core, the local door and server link, admission from machine grants, product doors, and the Teams server's neutral routes (company RFC 0008).",
|
|
6
6
|
"license": "MIT",
|
package/redact.mjs
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
// - the values this machine keeps in its custody files (KEY=value lines), which no detector knows; the files are named
|
|
4
4
|
// in `<supercode home>/custody.json` ({ "files": [...] }) and in SUPERCODE_CUSTODY_FILES (path-separated);
|
|
5
5
|
// - gitleaks' default rule set, vendored unchanged as redact/gitleaks-rules.json (its source and sha256 inside): each
|
|
6
|
-
// rule's keywords gate it, its secret group is what is replaced, and its entropy floor is kept
|
|
6
|
+
// rule's keywords gate it, its secret group is what is replaced, and its entropy floor is kept;
|
|
7
|
+
// - the tokens a Teams server mints itself (TEAM_TOKENS), which no gitleaks rule knows.
|
|
7
8
|
// Local files are never touched; only what is sent is redacted.
|
|
8
9
|
import { readFileSync, existsSync, statSync } from 'node:fs';
|
|
9
10
|
import { createHash } from 'node:crypto';
|
|
@@ -103,6 +104,13 @@ function longestMatch(source) {
|
|
|
103
104
|
const RULES = vendored.rules.map((rule) => { const regex = jsPattern(rule.regex); return { id: rule.id, regex, longest: regex ? longestMatch(regex.source) : Infinity, group: rule.secretGroup ?? null, keywords: (rule.keywords ?? []).map((k) => k.toLowerCase()), entropy: rule.entropy ?? null }; }).filter((rule) => rule.regex);
|
|
104
105
|
export const RULESET = { source: vendored.source, sha256: vendored.sha256, rules: RULES.length };
|
|
105
106
|
|
|
107
|
+
// The tokens a Teams server mints (sdk/volter-teams/server, sdk/teams/server): a credential `sct_<id>.<32 bytes>`
|
|
108
|
+
// (`sct_cred_<hex>.…`, the one three Codex session copies uploaded on 2026-09-30/10-01 carried, purged under D126), an
|
|
109
|
+
// invitation or install code `sci_[<id>.]<32 bytes>`, an app secret `sca_<32 bytes>`, an attachment token
|
|
110
|
+
// `sat_<id>.<32 bytes>`, each base64url, and a webhook signing secret `whsec_<32 bytes, base64>`. Each is replaced
|
|
111
|
+
// whole, by a marker naming its kind.
|
|
112
|
+
const TEAM_TOKENS = /\b(sct|sci|sca|sat)_(?:[A-Za-z]+_[0-9a-f]{32}\.)?[A-Za-z0-9_-]{43}(?![A-Za-z0-9_-])|\b(whsec)_[A-Za-z0-9+/]{43}=/g;
|
|
113
|
+
|
|
106
114
|
// Where each of many literals occurs, in one pass over the text (gitleaks finds its keywords the same way, with one
|
|
107
115
|
// automaton): a lookahead finds every position some literal starts at, and only those are compared literal by literal.
|
|
108
116
|
// Hundreds of separate includes() read a 5 MB tool result hundreds of times.
|
|
@@ -182,6 +190,7 @@ export function redactText(text, env = process.env) {
|
|
|
182
190
|
// Custody values are random, so one alternation of them gives the regex engine nothing to skip on: each is looked
|
|
183
191
|
// for on its own, which reads a 5 MB text in a few dozen milliseconds.
|
|
184
192
|
for (const { value, name } of custodyValues(env)) if (out.includes(value)) out = out.split(value).join(`[redacted:${name}]`);
|
|
193
|
+
if (/(?:sct|sci|sca|sat|whsec)_/.test(out)) out = out.replace(TEAM_TOKENS, (_, kind, hook) => `[redacted:teams-${kind ?? hook}-token]`);
|
|
185
194
|
// Every rule has keywords, so a text holding none of them is done (the one test is cheap; finding where each keyword
|
|
186
195
|
// occurs is not, and most texts are short and hold none).
|
|
187
196
|
let lower = out.toLowerCase();
|