Path: blob/main/components/gitpod-protocol/src/util/scrubbing.spec.ts
2500 views
/**1* Copyright (c) 2023 Gitpod GmbH. All rights reserved.2* Licensed under the GNU Affero General Public License (AGPL).3* See License.AGPL.txt in the project root for license information.4*/56import * as chai from "chai";7import { suite, test } from "@testdeck/mocha";8import { TrustedValue, scrubber } from "./scrubbing";9const expect = chai.expect;1011@suite12export class ScrubbingTest {13@test public testValue_EmptyString() {14expect(scrubber.scrub("")).to.equal("");15}16@test public testValue_Email() {17expect(scrubber.scrub("[email protected]")).to.equal("[redacted:email]");18}19@test public testValue_EmailInText() {20expect(scrubber.scrub("The email is [email protected] or [email protected]")).to.equal(21"The email is [redacted:email] or [redacted:email]",22);23}2425@test public testKeyValue_Email() {26expect(scrubber.scrub({ email: "testvalue" })).to.deep.equal({ email: "[redacted]" });27}28@test public testKeyValue_AuthorEmail() {29expect(scrubber.scrub({ author_email: "testvalue" })).to.deep.equal({ author_email: "[redacted]" });30}31@test public testKeyValue_Token() {32expect(scrubber.scrub({ token: "testvalue" })).to.deep.equal({ token: "[redacted]" });33}34@test public testKeyValue_OwnerToken() {35expect(scrubber.scrub({ owner_token: "testvalue" })).to.deep.equal({ owner_token: "[redacted]" });36}3738@test public testKeyValue_NestedObject() {39expect(scrubber.scrub({ key: { owner_token: "testvalue" } }, true)).to.deep.equal({40key: { owner_token: "[redacted]" },41});42}43@test public testKeyValue_NoNestedObject() {44expect(scrubber.scrub({ key: { owner_token: "testvalue" } }, false)).to.deep.equal({45key: "[redacted:nested:object}]",46});47}4849@test public testKeyValue_NestedArray() {50expect(scrubber.scrub([["[email protected]"]])).to.deep.equal([["[redacted:email]"]]);51}5253@test public testKeyValue_NoNestedArray() {54expect(scrubber.scrub([["[email protected]"]], false)).to.deep.equal(["[redacted:nested:array]"]);55}5657@test public testKeyValue_Scrubbable() {58const scrubbedValue = new TrustedValue(scrubber.scrubValue("[email protected]"));59expect(scrubber.scrub({ key: scrubbedValue })).to.deep.equal({ key: "[redacted:email]" });60}6162@test public testAnalyticsProperties_URLScrubbing() {63// Test case that mirrors the analytics.track() usage pattern64const mockInstance = {65id: "test-instance-123",66workspaceId: "test-workspace-456",67stoppingTime: "2023-01-01T00:00:00.000Z",68status: {69conditions: [70{71message:72"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):",73},74{75message: "Another error with URL: https://github.com/user/repo.git",76},77{78message: "Error without URL",79},80{81message: "API call to https://api.example.com/endpoint failed",82},83],84timeout: false,85},86};8788// This mirrors the exact usage in workspace-instance-controller.ts89const scrubbedProperties = scrubber.scrub({90instanceId: mockInstance.id,91workspaceId: mockInstance.workspaceId,92stoppingTime: new Date(mockInstance.stoppingTime),93conditions: mockInstance.status.conditions,94timeout: mockInstance.status.timeout,95});9697// Verify workspaceId is hashed (field-based scrubbing)98expect(scrubbedProperties.workspaceId).to.match(/^\[redacted:md5:[a-f0-9]{32}\]$/);99100// Verify instanceId is not scrubbed (not in sensitive fields)101expect(scrubbedProperties.instanceId).to.equal("test-instance-123");102103// Verify URLs in nested conditions are hashed (pattern-based scrubbing)104expect(scrubbedProperties.conditions[0].message).to.include("[redacted:md5:");105expect(scrubbedProperties.conditions[0].message).to.include(":url]");106expect(scrubbedProperties.conditions[0].message).to.not.include("gitlab.com");107108expect(scrubbedProperties.conditions[1].message).to.include("[redacted:md5:");109expect(scrubbedProperties.conditions[1].message).to.include(":url]");110expect(scrubbedProperties.conditions[1].message).to.not.include("github.com");111112// Verify non-URL message is unchanged113expect(scrubbedProperties.conditions[2].message).to.equal("Error without URL");114115// Verify non-.git URL is NOT scrubbed116expect(scrubbedProperties.conditions[3].message).to.equal(117"API call to https://api.example.com/endpoint failed",118);119expect(scrubbedProperties.conditions[3].message).to.not.include("[redacted:md5:");120121// Verify other properties are preserved122expect(scrubbedProperties.timeout).to.equal(false);123// Date objects get converted to empty objects by the scrubber since they don't have enumerable properties124expect(scrubbedProperties.stoppingTime).to.be.an("object");125}126127@test public testURL_PatternScrubbing() {128// Test individual URL scrubbing for .git URLs129const urlMessage = "git clone https://gitlab.com/acme-corp/web/frontend/services/deployment-manager.git failed";130const scrubbedMessage = scrubber.scrubValue(urlMessage);131132expect(scrubbedMessage).to.include("[redacted:md5:");133expect(scrubbedMessage).to.include(":url]");134expect(scrubbedMessage).to.not.include("gitlab.com");135expect(scrubbedMessage).to.include("git clone");136expect(scrubbedMessage).to.include("failed");137}138139@test public testURL_NonGitURLsNotScrubbed() {140// Test that non-.git URLs are NOT scrubbed141const apiMessage = "API call to https://api.example.com/endpoint failed";142const scrubbedMessage = scrubber.scrubValue(apiMessage);143144// Non-.git URLs should remain unchanged145expect(scrubbedMessage).to.equal("API call to https://api.example.com/endpoint failed");146expect(scrubbedMessage).to.not.include("[redacted:md5:");147}148149@test public testURL_MixedURLTypes() {150// Test message with both .git and non-.git URLs151const mixedMessage = "Clone from https://github.com/user/repo.git then visit https://docs.gitpod.io/configure";152const scrubbedMessage = scrubber.scrubValue(mixedMessage);153154// .git URL should be scrubbed155expect(scrubbedMessage).to.include("[redacted:md5:");156expect(scrubbedMessage).to.include(":url]");157expect(scrubbedMessage).to.not.include("github.com/user/repo.git");158159// Non-.git URL should remain unchanged160expect(scrubbedMessage).to.include("https://docs.gitpod.io/configure");161}162163@test public testURL_HttpGitURLs() {164// Test that http:// .git URLs are also scrubbed165const httpMessage = "git clone http://internal-git.company.com/project.git";166const scrubbedMessage = scrubber.scrubValue(httpMessage);167168expect(scrubbedMessage).to.include("[redacted:md5:");169expect(scrubbedMessage).to.include(":url]");170expect(scrubbedMessage).to.not.include("internal-git.company.com");171}172}173module.exports = new ScrubbingTest();174175176