e0e362d700
SDK Tests / changes (push) Successful in 2m29s
Real E2E Tests / changes (push) Successful in 2m29s
Deploy Docs Pages / build (push) Has been cancelled
Deploy Docs Pages / deploy (push) Has been cancelled
Real E2E Tests / JavaScript E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Python E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Java E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / C# E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Go E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Real E2E CI (push) Has been cancelled
SDK Tests / SDK CI (push) Has been cancelled
SDK Tests / CLI Tests (push) Has been cancelled
SDK Tests / Python SDK Quality (code-interpreter) (push) Has been cancelled
SDK Tests / Python SDK Quality (sandbox) (push) Has been cancelled
SDK Tests / Python SDK Tests (code-interpreter) (push) Has been cancelled
SDK Tests / JavaScript SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / JavaScript SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Python SDK Tests (sandbox) (push) Has been cancelled
SDK Tests / CLI Quality (push) Has been cancelled
SDK Tests / Kotlin SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Kotlin SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / C# SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / C# SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Go SDK Quality And Tests (push) Has been cancelled
120 lines
3.9 KiB
Go
120 lines
3.9 KiB
Go
// Copyright 2026 Alibaba Group Holding Ltd.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package log
|
|
|
|
import "regexp"
|
|
|
|
var sanitizePatterns = []struct {
|
|
re *regexp.Regexp
|
|
repl string
|
|
}{
|
|
// === URL / header / connection-string patterns ===
|
|
|
|
// URL credentials: scheme://user:password@host
|
|
{
|
|
regexp.MustCompile(`([a-zA-Z][a-zA-Z0-9+.-]*://)[^/\s:@]+:[^/\s:@]+@`),
|
|
`${1}****:****@`,
|
|
},
|
|
// Authorization: Bearer/Basic/Token/ApiKey header value
|
|
{
|
|
regexp.MustCompile(`(?i)(Authorization\s*:\s*(?:Bearer|Basic|Token|ApiKey|apiKey)\s+)\S+`),
|
|
`${1}****`,
|
|
},
|
|
// Azure storage AccountKey / SharedAccessKey (stop at ; " ' whitespace)
|
|
{
|
|
regexp.MustCompile(`((?:Account|SharedAccess)Key\s*=\s*)[^;"'\s]+`),
|
|
`${1}****`,
|
|
},
|
|
|
|
// === Long-flag sensitive options: --flag value or --flag=value ===
|
|
// Flag names listed longest-first so RE2 picks the right match.
|
|
// Requiring [\s=] after the flag name prevents --password from matching
|
|
// --password-stdin (the trailing - isn't whitespace or =).
|
|
|
|
{
|
|
regexp.MustCompile(
|
|
`(--(?:access-key-id|access-key-secret|access-token|access-key|` +
|
|
`secret-access-key|secret-key|secret-id|secret|` +
|
|
`aws-secret-access-key|private-key|client-secret|refresh-token|` +
|
|
`sentry-token|credential|password|passwd|` +
|
|
`api-key|apikey|token|` +
|
|
`ak|sk))` +
|
|
`([\s=])\s*` +
|
|
`(?:"[^"]*"|'[^']*'|\S+)?`,
|
|
),
|
|
`${1}${2}****`,
|
|
},
|
|
|
|
// === Environment variable assignments with sensitive names ===
|
|
|
|
{
|
|
regexp.MustCompile(
|
|
`\b(PASSWORD|PASSWD|SECRET|TOKEN|API_KEY|APIKEY|AUTH_TOKEN|ACCESS_TOKEN|` +
|
|
`PRIVATE_KEY|CLIENT_SECRET|REFRESH_TOKEN|CREDENTIAL|AUTH_KEY|SECRET_KEY|SECRET_ID|` +
|
|
// Cloud-provider specific
|
|
`ACCESS_KEY_ID|ACCESS_KEY_SECRET|SECRET_ACCESS_KEY|` +
|
|
`AWS_ACCESS_KEY_ID|AWS_SECRET_ACCESS_KEY|AWS_SESSION_TOKEN|` +
|
|
`ALIBABA_CLOUD_ACCESS_KEY_ID|ALIBABA_CLOUD_ACCESS_KEY_SECRET|ALIBABA_CLOUD_SECRET_KEY|` +
|
|
`ALICLOUD_ACCESS_KEY_ID|ALICLOUD_ACCESS_KEY_SECRET|ALICLOUD_SECRET_KEY|` +
|
|
`TENCENTCLOUD_SECRET_ID|TENCENTCLOUD_SECRET_KEY|` +
|
|
`HUAWEICLOUD_ACCESS_KEY_ID|HUAWEICLOUD_SECRET_ACCESS_KEY|` +
|
|
`CLOUD_ACCESS_KEY_ID|CLOUD_SECRET_KEY|CLOUD_API_KEY|CLOUD_API_SECRET|` +
|
|
`RAM_ACCESS_KEY_ID|RAM_ACCESS_KEY_SECRET|` +
|
|
`OTS_ACCESS_KEY_ID|OTS_ACCESS_KEY_SECRET|` +
|
|
`ACCOUNT_KEY|SHARED_ACCESS_KEY|AZURE_STORAGE_KEY|` +
|
|
`GCP_CREDENTIALS|GOOGLE_APPLICATION_CREDENTIALS|` +
|
|
`DOCKER_PASSWORD|DOCKER_TOKEN|REGISTRY_PASSWORD` +
|
|
`)\s*=\s*(?:"[^"]*"|'[^']*'|\S+)`,
|
|
),
|
|
`${1}=****`,
|
|
},
|
|
|
|
// === Bare cloud access key matching (prefix-specific, low false-positive) ===
|
|
|
|
// Alibaba Cloud AccessKey ID: LTAI + 16~32 alphanumeric
|
|
{
|
|
regexp.MustCompile(`\bLTAI[a-zA-Z0-9]{16,32}\b`),
|
|
`LTAI****`,
|
|
},
|
|
// AWS Access Key ID: AKIA + 16 uppercase
|
|
{
|
|
regexp.MustCompile(`\bAKIA[A-Z0-9]{16}\b`),
|
|
`AKIA****`,
|
|
},
|
|
// Tencent Cloud Secret ID: AKID + 16~48 alphanumeric
|
|
{
|
|
regexp.MustCompile(`\bAKID[a-zA-Z0-9]{16,48}\b`),
|
|
`AKID****`,
|
|
},
|
|
}
|
|
|
|
// SanitizeCommand masks sensitive values (passwords, tokens, keys, credentials)
|
|
// in a shell command string so it is safe to log.
|
|
func SanitizeCommand(cmd string) string {
|
|
for _, p := range sanitizePatterns {
|
|
cmd = p.re.ReplaceAllString(cmd, p.repl)
|
|
}
|
|
return cmd
|
|
}
|
|
|
|
// MaskToken returns a partially masked token for logging.
|
|
// Shows first 4 and last 4 characters; returns "****" for tokens 8 chars or shorter.
|
|
func MaskToken(token string) string {
|
|
if len(token) <= 8 {
|
|
return "****"
|
|
}
|
|
return token[:4] + "****" + token[len(token)-4:]
|
|
}
|