@uniglot/wont-let-you-see 0.3.0 → 1.0.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 +45 -34
- package/dist/index.js +3 -0
- package/package.json +1 -1
- package/patterns/aws.json +1 -0
- package/patterns/common.json +11 -1
- package/patterns/kubernetes.json +0 -1
- package/src/__tests__/masker.test.ts +2 -1
- package/src/__tests__/patterns.test.ts +2 -10
- package/src/index.ts +9 -0
package/README.md
CHANGED
|
@@ -89,46 +89,53 @@ The plugin automatically masks output from:
|
|
|
89
89
|
|
|
90
90
|
### AWS Resources
|
|
91
91
|
|
|
92
|
-
| Pattern Type
|
|
93
|
-
|
|
|
94
|
-
| `arn`
|
|
95
|
-
| `eks-cluster`
|
|
96
|
-
| `account-id`
|
|
97
|
-
| `access-key-id`
|
|
98
|
-
| `
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
110
|
-
| `
|
|
111
|
-
| `
|
|
112
|
-
| `
|
|
113
|
-
| `
|
|
114
|
-
| `vpn-
|
|
115
|
-
| `
|
|
92
|
+
| Pattern Type | Description | Example |
|
|
93
|
+
| ------------------- | ---------------------------- | ------------------------------------------------------- |
|
|
94
|
+
| `arn` | Generic AWS ARNs | `arn:aws:iam::123456789012:user/admin` |
|
|
95
|
+
| `eks-cluster` | EKS Cluster ARNs | `arn:aws:eks:us-west-2:123456789012:cluster/my-cluster` |
|
|
96
|
+
| `account-id` | AWS Account IDs (contextual) | `"OwnerId": "123456789012"` |
|
|
97
|
+
| `access-key-id` | AWS Access Key IDs | `AKIAIOSFODNN7EXAMPLE` |
|
|
98
|
+
| `secret-access-key` | AWS Secret Access Keys | `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY` |
|
|
99
|
+
| `vpc` | VPC IDs | `vpc-0123456789abcdef0` |
|
|
100
|
+
| `subnet` | Subnet IDs | `subnet-0123456789abcdef0` |
|
|
101
|
+
| `security-group` | Security Group IDs | `sg-0123456789abcdef0` |
|
|
102
|
+
| `internet-gateway` | Internet Gateway IDs | `igw-0123456789abcdef0` |
|
|
103
|
+
| `route-table` | Route Table IDs | `rtb-0123456789abcdef0` |
|
|
104
|
+
| `nat-gateway` | NAT Gateway IDs | `nat-0123456789abcdef0` |
|
|
105
|
+
| `network-acl` | Network ACL IDs | `acl-0123456789abcdef0` |
|
|
106
|
+
| `ec2-instance` | EC2 Instance IDs | `i-0123456789abcdef0` |
|
|
107
|
+
| `ami` | AMI IDs | `ami-0123456789abcdef0` |
|
|
108
|
+
| `ebs` | EBS Volume IDs | `vol-0123456789abcdef0` |
|
|
109
|
+
| `snapshot` | EBS Snapshot IDs | `snap-0123456789abcdef0` |
|
|
110
|
+
| `eni` | Network Interface IDs | `eni-0123456789abcdef0` |
|
|
111
|
+
| `vpc-endpoint` | VPC Endpoint IDs | `vpce-0123456789abcdef0` |
|
|
112
|
+
| `transit-gateway` | Transit Gateway IDs | `tgw-0123456789abcdef0` |
|
|
113
|
+
| `customer-gateway` | Customer Gateway IDs | `cgw-0123456789abcdef0` |
|
|
114
|
+
| `vpn-gateway` | VPN Gateway IDs | `vgw-0123456789abcdef0` |
|
|
115
|
+
| `vpn-connection` | VPN Connection IDs | `vpn-0123456789abcdef0` |
|
|
116
|
+
| `ecr-repo` | ECR Repository URIs | `123456789012.dkr.ecr.us-west-2.amazonaws.com/my-repo` |
|
|
116
117
|
|
|
117
118
|
### Kubernetes Resources (EKS)
|
|
118
119
|
|
|
119
|
-
| Pattern Type | Description
|
|
120
|
-
| -------------- |
|
|
121
|
-
| `k8s-
|
|
122
|
-
| `k8s-
|
|
123
|
-
| `k8s-node` | EKS Node Names | `ip-10-0-1-123.compute.internal` |
|
|
120
|
+
| Pattern Type | Description | Example |
|
|
121
|
+
| -------------- | ------------------------- | ---------------------------------- |
|
|
122
|
+
| `k8s-endpoint` | EKS Cluster API Endpoints | `https://ABC123.eks.amazonaws.com` |
|
|
123
|
+
| `k8s-node` | EKS Node Names | `ip-10-0-1-123.compute.internal` |
|
|
124
124
|
|
|
125
125
|
### Common Patterns
|
|
126
126
|
|
|
127
|
-
| Pattern Type
|
|
128
|
-
|
|
|
129
|
-
| `ipv4`
|
|
130
|
-
| `private-key`
|
|
131
|
-
| `api-key`
|
|
127
|
+
| Pattern Type | Description | Example |
|
|
128
|
+
| --------------------- | --------------------------------------------- | ----------------------------------------------------------------- |
|
|
129
|
+
| `ipv4` | IPv4 Addresses (including IP portion of CIDR) | `192.168.1.1`, `10.0.0.0/16` → `#(ipv4-1)/16` |
|
|
130
|
+
| `private-key` | Private Key Blocks (entire key) | `-----BEGIN RSA PRIVATE KEY-----...-----END RSA PRIVATE KEY-----` |
|
|
131
|
+
| `api-key` | API Keys (contextual) | `"api_key": "sk-..."` |
|
|
132
|
+
| `phone-us` | US Phone Numbers | `+1-555-123-4567`, `(555) 123-4567` |
|
|
133
|
+
| `phone-kr` | South Korean Phone Numbers | `010-1234-5678`, `+82-10-1234-5678` |
|
|
134
|
+
| `phone-international` | International Phone Numbers | `+44 20 7946 0958` |
|
|
135
|
+
| `email` | Email Addresses | `user@example.com` |
|
|
136
|
+
| `uuid` | UUID/GUID | `550e8400-e29b-41d4-a716-446655440000` |
|
|
137
|
+
| `jwt` | JWT Tokens | `eyJhbGciOiJIUzI1NiIs...` |
|
|
138
|
+
| `base64-secret` | Base64-encoded Secrets (contextual) | `"secret": "SGVsbG8gV29ybGQ="` |
|
|
132
139
|
|
|
133
140
|
## Token Format
|
|
134
141
|
|
|
@@ -140,6 +147,10 @@ Examples:
|
|
|
140
147
|
- `10.0.0.1` → `#(ipv4-1)`
|
|
141
148
|
- `10.0.0.0/16` → `#(ipv4-1)/16` (subnet mask preserved)
|
|
142
149
|
- `AKIAIOSFODNN7EXAMPLE` → `#(access-key-id-1)`
|
|
150
|
+
- `wJalrXUtnFEMI/K7MDENG...` → `#(secret-access-key-1)`
|
|
151
|
+
- `user@example.com` → `#(email-1)`
|
|
152
|
+
- `+1-555-123-4567` → `#(phone-us-1)`
|
|
153
|
+
- `eyJhbGciOiJIUzI1NiIs...` → `#(jwt-1)`
|
|
143
154
|
- Entire private key block → `#(private-key-1)`
|
|
144
155
|
|
|
145
156
|
## How It Works
|
package/dist/index.js
CHANGED
|
@@ -349,6 +349,9 @@ var plugin = async (input) => {
|
|
|
349
349
|
return;
|
|
350
350
|
}
|
|
351
351
|
output.output = mask(hookInput.sessionID, output.output);
|
|
352
|
+
if (output.metadata?.output) {
|
|
353
|
+
output.metadata.output = mask(hookInput.sessionID, output.metadata.output);
|
|
354
|
+
}
|
|
352
355
|
},
|
|
353
356
|
"chat.message": async (hookInput, output) => {
|
|
354
357
|
for (const part of output.parts) {
|
package/package.json
CHANGED
package/patterns/aws.json
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"contextual": true
|
|
7
7
|
},
|
|
8
8
|
"access-key-id": "(?:^|[^A-Z0-9])(?:AKIA|ABIA|ACCA|ASIA)[A-Z0-9]{16}(?:[^A-Z0-9]|$)",
|
|
9
|
+
"secret-access-key": "(?:^|[^A-Za-z0-9+/])[A-Za-z0-9+/]{40}(?:[^A-Za-z0-9+/]|$)",
|
|
9
10
|
"vpc": "^vpc-[0-9a-f]{8,17}$",
|
|
10
11
|
"subnet": "^subnet-[0-9a-f]{8,17}$",
|
|
11
12
|
"security-group": "^sg-[0-9a-f]{8,17}$",
|
package/patterns/common.json
CHANGED
|
@@ -4,5 +4,15 @@
|
|
|
4
4
|
"pattern": "\"(?:api_key|apiKey|secret_key|secretKey|access_token|auth_token|password|token)\":\\s*\"([^\"]+)\"",
|
|
5
5
|
"contextual": true
|
|
6
6
|
},
|
|
7
|
-
"ipv4": "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
|
|
7
|
+
"ipv4": "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$",
|
|
8
|
+
"phone-us": "^(?:\\+1[-\\s.]?)?(?:\\(?[2-9][0-9]{2}\\)?[-\\s.]?)?[2-9][0-9]{2}[-\\s.]?[0-9]{4}$",
|
|
9
|
+
"phone-kr": "^(?:\\+82[-\\s.]?|0)?(?:1[0-9]|2|3[1-3]|4[1-4]|5[1-5]|6[1-4])[-\\s.]?[0-9]{3,4}[-\\s.]?[0-9]{4}$",
|
|
10
|
+
"phone-international": "^\\+[1-9][0-9]{0,2}[-\\s.]?(?:[0-9][-\\s.]?){6,14}[0-9]$",
|
|
11
|
+
"email": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
|
|
12
|
+
"uuid": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
|
|
13
|
+
"jwt": "^eyJ[A-Za-z0-9_-]*\\.eyJ[A-Za-z0-9_-]*\\.[A-Za-z0-9_-]*$",
|
|
14
|
+
"base64-secret": {
|
|
15
|
+
"pattern": "\"(?:secret|password|credential|private_key|privateKey|encryption_key|encryptionKey|signing_key|signingKey)\":\\s*\"([A-Za-z0-9+/]{32,}={0,2})\"",
|
|
16
|
+
"contextual": true
|
|
17
|
+
}
|
|
8
18
|
}
|
package/patterns/kubernetes.json
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
{
|
|
2
|
-
"k8s-token": "^eyJ[A-Za-z0-9_-]*\\.eyJ[A-Za-z0-9_-]*\\.[A-Za-z0-9_-]*$",
|
|
3
2
|
"k8s-endpoint": "^https:\\/\\/[A-Z0-9]+\\.[a-z0-9-]+\\.eks\\.amazonaws\\.com$",
|
|
4
3
|
"k8s-endpoint-kubeconfig": {
|
|
5
4
|
"pattern": "^https:\\/\\/[0-9A-F]{32}\\.[a-z]{2}-[a-z]+-\\d\\.eks\\.amazonaws\\.com$",
|
|
@@ -172,7 +172,8 @@ describe("masker", () => {
|
|
|
172
172
|
});
|
|
173
173
|
|
|
174
174
|
it("should not mask ARN when both eks-cluster and arn are revealed", () => {
|
|
175
|
-
process.env.WONT_LET_YOU_SEE_REVEALED_PATTERNS =
|
|
175
|
+
process.env.WONT_LET_YOU_SEE_REVEALED_PATTERNS =
|
|
176
|
+
"eks-cluster,arn,phone-us";
|
|
176
177
|
resetConfig();
|
|
177
178
|
|
|
178
179
|
const input =
|
|
@@ -210,14 +210,6 @@ describe("Kubernetes Patterns", () => {
|
|
|
210
210
|
resetPatternCache();
|
|
211
211
|
});
|
|
212
212
|
|
|
213
|
-
describe("Service Account Token", () => {
|
|
214
|
-
it("should match JWT format", () => {
|
|
215
|
-
const jwt =
|
|
216
|
-
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tYWJjZGUiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjEyMzQ1Njc4LTEyMzQtMTIzNC0xMjM0LTEyMzQ1Njc4OTAxMiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.signature";
|
|
217
|
-
expect(getPattern("k8s-token").test(jwt)).toBe(true);
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
|
|
221
213
|
describe("Node Names", () => {
|
|
222
214
|
it("should match AWS node name", () => {
|
|
223
215
|
expect(
|
|
@@ -334,8 +326,8 @@ describe("loadPatterns", () => {
|
|
|
334
326
|
|
|
335
327
|
it("should load Kubernetes patterns", () => {
|
|
336
328
|
const patterns = loadPatterns();
|
|
337
|
-
const
|
|
338
|
-
expect(
|
|
329
|
+
const k8sNodePattern = patterns.find((p) => p.name === "k8s-node");
|
|
330
|
+
expect(k8sNodePattern).toBeDefined();
|
|
339
331
|
});
|
|
340
332
|
|
|
341
333
|
it("should load common patterns", () => {
|
package/src/index.ts
CHANGED
|
@@ -30,7 +30,16 @@ export const plugin: Plugin = async (input: PluginInput): Promise<Hooks> => {
|
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
// Mask output sent to LLM
|
|
33
34
|
output.output = mask(hookInput.sessionID, output.output);
|
|
35
|
+
|
|
36
|
+
// Also mask TUI display (metadata.output is used as fallback in TUI rendering)
|
|
37
|
+
if (output.metadata?.output) {
|
|
38
|
+
output.metadata.output = mask(
|
|
39
|
+
hookInput.sessionID,
|
|
40
|
+
output.metadata.output,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
34
43
|
},
|
|
35
44
|
|
|
36
45
|
"chat.message": async (hookInput, output) => {
|