Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/gitpod-protocol/src/util/scrubbing.spec.ts
2500 views
1
/**
2
* Copyright (c) 2023 Gitpod GmbH. All rights reserved.
3
* Licensed under the GNU Affero General Public License (AGPL).
4
* See License.AGPL.txt in the project root for license information.
5
*/
6
7
import * as chai from "chai";
8
import { suite, test } from "@testdeck/mocha";
9
import { TrustedValue, scrubber } from "./scrubbing";
10
const expect = chai.expect;
11
12
@suite
13
export class ScrubbingTest {
14
@test public testValue_EmptyString() {
15
expect(scrubber.scrub("")).to.equal("");
16
}
17
@test public testValue_Email() {
18
expect(scrubber.scrub("[email protected]")).to.equal("[redacted:email]");
19
}
20
@test public testValue_EmailInText() {
21
expect(scrubber.scrub("The email is [email protected] or [email protected]")).to.equal(
22
"The email is [redacted:email] or [redacted:email]",
23
);
24
}
25
26
@test public testKeyValue_Email() {
27
expect(scrubber.scrub({ email: "testvalue" })).to.deep.equal({ email: "[redacted]" });
28
}
29
@test public testKeyValue_AuthorEmail() {
30
expect(scrubber.scrub({ author_email: "testvalue" })).to.deep.equal({ author_email: "[redacted]" });
31
}
32
@test public testKeyValue_Token() {
33
expect(scrubber.scrub({ token: "testvalue" })).to.deep.equal({ token: "[redacted]" });
34
}
35
@test public testKeyValue_OwnerToken() {
36
expect(scrubber.scrub({ owner_token: "testvalue" })).to.deep.equal({ owner_token: "[redacted]" });
37
}
38
39
@test public testKeyValue_NestedObject() {
40
expect(scrubber.scrub({ key: { owner_token: "testvalue" } }, true)).to.deep.equal({
41
key: { owner_token: "[redacted]" },
42
});
43
}
44
@test public testKeyValue_NoNestedObject() {
45
expect(scrubber.scrub({ key: { owner_token: "testvalue" } }, false)).to.deep.equal({
46
key: "[redacted:nested:object}]",
47
});
48
}
49
50
@test public testKeyValue_NestedArray() {
51
expect(scrubber.scrub([["[email protected]"]])).to.deep.equal([["[redacted:email]"]]);
52
}
53
54
@test public testKeyValue_NoNestedArray() {
55
expect(scrubber.scrub([["[email protected]"]], false)).to.deep.equal(["[redacted:nested:array]"]);
56
}
57
58
@test public testKeyValue_Scrubbable() {
59
const scrubbedValue = new TrustedValue(scrubber.scrubValue("[email protected]"));
60
expect(scrubber.scrub({ key: scrubbedValue })).to.deep.equal({ key: "[redacted:email]" });
61
}
62
63
@test public testAnalyticsProperties_URLScrubbing() {
64
// Test case that mirrors the analytics.track() usage pattern
65
const mockInstance = {
66
id: "test-instance-123",
67
workspaceId: "test-workspace-456",
68
stoppingTime: "2023-01-01T00:00:00.000Z",
69
status: {
70
conditions: [
71
{
72
message:
73
"Content initialization failed: cannot initialize workspace: git initializer gitClone: git clone --depth=1 --shallow-submodules https://gitlab.com/acme-corp/web/frontend/services/deployment-manager.git --config http.version=HTTP/1.1 . failed (exit status 128):",
74
},
75
{
76
message: "Another error with URL: https://github.com/user/repo.git",
77
},
78
{
79
message: "Error without URL",
80
},
81
{
82
message: "API call to https://api.example.com/endpoint failed",
83
},
84
],
85
timeout: false,
86
},
87
};
88
89
// This mirrors the exact usage in workspace-instance-controller.ts
90
const scrubbedProperties = scrubber.scrub({
91
instanceId: mockInstance.id,
92
workspaceId: mockInstance.workspaceId,
93
stoppingTime: new Date(mockInstance.stoppingTime),
94
conditions: mockInstance.status.conditions,
95
timeout: mockInstance.status.timeout,
96
});
97
98
// Verify workspaceId is hashed (field-based scrubbing)
99
expect(scrubbedProperties.workspaceId).to.match(/^\[redacted:md5:[a-f0-9]{32}\]$/);
100
101
// Verify instanceId is not scrubbed (not in sensitive fields)
102
expect(scrubbedProperties.instanceId).to.equal("test-instance-123");
103
104
// Verify URLs in nested conditions are hashed (pattern-based scrubbing)
105
expect(scrubbedProperties.conditions[0].message).to.include("[redacted:md5:");
106
expect(scrubbedProperties.conditions[0].message).to.include(":url]");
107
expect(scrubbedProperties.conditions[0].message).to.not.include("gitlab.com");
108
109
expect(scrubbedProperties.conditions[1].message).to.include("[redacted:md5:");
110
expect(scrubbedProperties.conditions[1].message).to.include(":url]");
111
expect(scrubbedProperties.conditions[1].message).to.not.include("github.com");
112
113
// Verify non-URL message is unchanged
114
expect(scrubbedProperties.conditions[2].message).to.equal("Error without URL");
115
116
// Verify non-.git URL is NOT scrubbed
117
expect(scrubbedProperties.conditions[3].message).to.equal(
118
"API call to https://api.example.com/endpoint failed",
119
);
120
expect(scrubbedProperties.conditions[3].message).to.not.include("[redacted:md5:");
121
122
// Verify other properties are preserved
123
expect(scrubbedProperties.timeout).to.equal(false);
124
// Date objects get converted to empty objects by the scrubber since they don't have enumerable properties
125
expect(scrubbedProperties.stoppingTime).to.be.an("object");
126
}
127
128
@test public testURL_PatternScrubbing() {
129
// Test individual URL scrubbing for .git URLs
130
const urlMessage = "git clone https://gitlab.com/acme-corp/web/frontend/services/deployment-manager.git failed";
131
const scrubbedMessage = scrubber.scrubValue(urlMessage);
132
133
expect(scrubbedMessage).to.include("[redacted:md5:");
134
expect(scrubbedMessage).to.include(":url]");
135
expect(scrubbedMessage).to.not.include("gitlab.com");
136
expect(scrubbedMessage).to.include("git clone");
137
expect(scrubbedMessage).to.include("failed");
138
}
139
140
@test public testURL_NonGitURLsNotScrubbed() {
141
// Test that non-.git URLs are NOT scrubbed
142
const apiMessage = "API call to https://api.example.com/endpoint failed";
143
const scrubbedMessage = scrubber.scrubValue(apiMessage);
144
145
// Non-.git URLs should remain unchanged
146
expect(scrubbedMessage).to.equal("API call to https://api.example.com/endpoint failed");
147
expect(scrubbedMessage).to.not.include("[redacted:md5:");
148
}
149
150
@test public testURL_MixedURLTypes() {
151
// Test message with both .git and non-.git URLs
152
const mixedMessage = "Clone from https://github.com/user/repo.git then visit https://docs.gitpod.io/configure";
153
const scrubbedMessage = scrubber.scrubValue(mixedMessage);
154
155
// .git URL should be scrubbed
156
expect(scrubbedMessage).to.include("[redacted:md5:");
157
expect(scrubbedMessage).to.include(":url]");
158
expect(scrubbedMessage).to.not.include("github.com/user/repo.git");
159
160
// Non-.git URL should remain unchanged
161
expect(scrubbedMessage).to.include("https://docs.gitpod.io/configure");
162
}
163
164
@test public testURL_HttpGitURLs() {
165
// Test that http:// .git URLs are also scrubbed
166
const httpMessage = "git clone http://internal-git.company.com/project.git";
167
const scrubbedMessage = scrubber.scrubValue(httpMessage);
168
169
expect(scrubbedMessage).to.include("[redacted:md5:");
170
expect(scrubbedMessage).to.include(":url]");
171
expect(scrubbedMessage).to.not.include("internal-git.company.com");
172
}
173
}
174
module.exports = new ScrubbingTest();
175
176