pi-git-auth 1.0.1 → 1.1.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 CHANGED
@@ -36,6 +36,10 @@ TypeScript directly.
36
36
  - A `tool_call` hook watches every `bash` invocation. When an active
37
37
  account exists and the command runs `git`, the command is rewritten to
38
38
  authenticate that account's host (see [git auth](#git-auth)).
39
+ - A `tool_result` hook masks token-shaped strings (GitHub/GitLab PATs,
40
+ URL-embedded credentials) in **every** tool output before it enters
41
+ the transcript — an accidental `env` dump or config echo can never
42
+ print the live token into the conversation.
39
43
 
40
44
  ## Layout
41
45
 
@@ -50,6 +54,7 @@ github.ts GitHub REST client
50
54
  gitlab.ts GitLab REST client
51
55
  details.ts read-only repo details overlay (tree + commits + metadata)
52
56
  git-gate.ts command rewriting that injects the token for a host
57
+ redact.ts secret redaction of tool outputs (PAT / URL-credential patterns)
53
58
  ```
54
59
 
55
60
  ## Usage
package/index.ts CHANGED
@@ -5,6 +5,7 @@ import { loadStore, activeAccount } from "./store";
5
5
  import { SERVICES } from "./forge";
6
6
  import { findAccounts, setActiveAccount, statusDetail } from "./auth";
7
7
  import { instrumentGit } from "./git-gate";
8
+ import { redactSecrets } from "./redact";
8
9
  import { handleAuthCommand } from "./commands";
9
10
 
10
11
  export default function (pi: ExtensionAPI) {
@@ -20,6 +21,25 @@ export default function (pi: ExtensionAPI) {
20
21
  event.input.command = instrumentGit(event.input.command, host, acc.accessToken);
21
22
  });
22
23
 
24
+ // ------------------------------------------------------------------
25
+ // Secret redaction: never let token-shaped strings reach the
26
+ // transcript. The gate keeps the token out of argv and off disk,
27
+ // but any bash output (env dump, config echo) would otherwise land
28
+ // in the session file and the conversation.
29
+ // ------------------------------------------------------------------
30
+ pi.on("tool_result", (event) => {
31
+ let changed = false;
32
+ const content = event.content.map((block) => {
33
+ if (block.type !== "text") return block;
34
+ const text = redactSecrets(block.text);
35
+ if (text === block.text) return block;
36
+ changed = true;
37
+ return { ...block, text };
38
+ });
39
+ if (!changed) return;
40
+ return { content };
41
+ });
42
+
23
43
  // ------------------------------------------------------------------
24
44
  // /auth command
25
45
  // ------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-git-auth",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "pi coding-agent extension: git auth for GitHub and GitLab: keyring-stored login tokens, account switching, transparent git auth, repo list/create with details overlay",
5
5
  "license": "MIT",
6
6
  "author": "Carlo Onofrio",
@@ -22,8 +22,7 @@
22
22
  "files": [
23
23
  "*.ts",
24
24
  "README.md",
25
- "LICENSE",
26
- "preview.png"
25
+ "LICENSE"
27
26
  ],
28
27
  "engines": {
29
28
  "node": ">=20"
@@ -36,7 +35,6 @@
36
35
  "pi": {
37
36
  "extensions": [
38
37
  "./index.ts"
39
- ],
40
- "image": "https://raw.githubusercontent.com/comicrocharly/pi-git-auth/main/preview.png"
38
+ ]
41
39
  }
42
40
  }
package/redact.ts ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Secret redaction for tool results.
3
+ *
4
+ * The git gate keeps the active token out of argv and off disk, but a
5
+ * bash command (an `env` dump, a `git config` echo, a `printenv`) can
6
+ * still print it into the tool output, which then lands in the session
7
+ * transcript. This module masks token-shaped strings in tool results
8
+ * before they are stored, so an accidental echo can never put the live
9
+ * token into the conversation — and there is nothing to rotate because
10
+ * of it.
11
+ *
12
+ * Patterns (masked to a short fingerprint, e.g. `ghp_…7SAQ`):
13
+ * - GitHub classic PATs: gh[pousr]_ + 20+ base62
14
+ * - GitHub fine-grained PATs: github_pat_ + 30+
15
+ * - GitLab PATs: glpat- + 16+
16
+ * - URL-embedded credentials: user:secret@ — the secret part only
17
+ *
18
+ * Masking is idempotent: a masked string never matches the patterns
19
+ * again, so repeated passes are a no-op.
20
+ */
21
+
22
+ function maskTail(match: string, head: number): string {
23
+ return match.length <= head + 4 ? "***" : `${match.slice(0, head)}…${match.slice(-4)}`;
24
+ }
25
+
26
+ export function redactSecrets(text: string): string {
27
+ return text
28
+ .replace(/\bgh[pousr]_[A-Za-z0-9]{20,}/g, (m) => maskTail(m, 4))
29
+ .replace(/\bgithub_pat_[A-Za-z0-9_]{30,}/g, (m) => maskTail(m, 10))
30
+ .replace(/\bglpat-[A-Za-z0-9_-]{16,}/g, (m) => maskTail(m, 6))
31
+ .replace(/(\/\/[^/\s:@]+:)([^@\s]{4,})(@)/g, "$1***$3");
32
+ }
package/preview.png DELETED
Binary file