Skip to content

Commit c2bdc62

Browse files
authored
Merge branch 'main' into chore/coderabbit-triage-v0.2.4
2 parents 17e785b + 1c23b65 commit c2bdc62

4 files changed

Lines changed: 189 additions & 15 deletions

File tree

components/backend/gitlab/logger.go

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,20 @@ import (
1010
// TokenRedactionPlaceholder is used to replace sensitive tokens in logs
1111
const TokenRedactionPlaceholder = "[REDACTED]"
1212

13+
var (
14+
gitlabPATPattern = regexp.MustCompile(`glpat-[a-zA-Z0-9_-]+`)
15+
gitlabCIPattern = regexp.MustCompile(`gitlab-ci-token:\s*[a-zA-Z0-9_-]+`)
16+
bearerPattern = regexp.MustCompile(`Bearer\s+\S+`)
17+
oauthURLPattern = regexp.MustCompile(`oauth2:[^@]+@`)
18+
tokenURLPattern = regexp.MustCompile(`://[^:]+:[^@]+@`)
19+
)
20+
1321
// RedactToken removes sensitive token information from a string
1422
func RedactToken(s string) string {
15-
// GitLab PAT format: glpat-xxxxxxxxxxxxx
16-
gitlabPATPattern := regexp.MustCompile(`glpat-[a-zA-Z0-9_-]+`)
1723
s = gitlabPATPattern.ReplaceAllString(s, TokenRedactionPlaceholder)
18-
19-
// GitLab CI token format: gitlab-ci-token
20-
gitlabCIPattern := regexp.MustCompile(`gitlab-ci-token:\s*[a-zA-Z0-9_-]+`)
2124
s = gitlabCIPattern.ReplaceAllString(s, "gitlab-ci-token: "+TokenRedactionPlaceholder)
22-
23-
// Bearer tokens in Authorization headers
24-
bearerPattern := regexp.MustCompile(`Bearer\s+[a-zA-Z0-9_-]+`)
2525
s = bearerPattern.ReplaceAllString(s, "Bearer "+TokenRedactionPlaceholder)
26-
27-
// OAuth2 tokens in URLs: oauth2:TOKEN@
28-
oauthURLPattern := regexp.MustCompile(`oauth2:[^@]+@`)
2926
s = oauthURLPattern.ReplaceAllString(s, "oauth2:"+TokenRedactionPlaceholder+"@")
30-
31-
// Generic token pattern in URLs
32-
tokenURLPattern := regexp.MustCompile(`://[^:]+:[^@]+@`)
3327
s = tokenURLPattern.ReplaceAllString(s, "://"+TokenRedactionPlaceholder+":"+TokenRedactionPlaceholder+"@")
3428

3529
return s
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package gitlab
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"testing"
7+
)
8+
9+
func TestRedactToken_BearerJWT(t *testing.T) {
10+
jwt := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpM"
11+
input := "Authorization: Bearer " + jwt
12+
result := RedactToken(input)
13+
if strings.Contains(result, jwt) {
14+
t.Errorf("JWT token was not fully redacted: %s", result)
15+
}
16+
if !strings.Contains(result, "Bearer "+TokenRedactionPlaceholder) {
17+
t.Errorf("expected Bearer [REDACTED], got: %s", result)
18+
}
19+
}
20+
21+
func TestRedactToken_BearerBase64(t *testing.T) {
22+
base64Token := "dGhpcyBpcyBhIHRva2VuIHdpdGggcGFkZGluZw=="
23+
input := "Authorization: Bearer " + base64Token
24+
result := RedactToken(input)
25+
if strings.Contains(result, base64Token) {
26+
t.Errorf("base64 token was not fully redacted: %s", result)
27+
}
28+
if !strings.Contains(result, "Bearer "+TokenRedactionPlaceholder) {
29+
t.Errorf("expected Bearer [REDACTED], got: %s", result)
30+
}
31+
}
32+
33+
func TestRedactToken_BearerSimple(t *testing.T) {
34+
input := "Authorization: Bearer ghp_abc123def456"
35+
result := RedactToken(input)
36+
if strings.Contains(result, "ghp_abc123def456") {
37+
t.Errorf("simple token was not redacted: %s", result)
38+
}
39+
}
40+
41+
func TestSanitizeErrorMessage_RedactsTokenInError(t *testing.T) {
42+
token := "ghp_secrettoken123"
43+
err := fmt.Errorf("failed to fetch: Bearer %s was rejected", token)
44+
result := SanitizeErrorMessage(err)
45+
if strings.Contains(result, token) {
46+
t.Errorf("token leaked in sanitized error message: %s", result)
47+
}
48+
}
49+
50+
func TestSanitizeErrorMessage_NilError(t *testing.T) {
51+
result := SanitizeErrorMessage(nil)
52+
if result != "" {
53+
t.Errorf("expected empty string for nil error, got: %s", result)
54+
}
55+
}

components/backend/handlers/sessions.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"unicode/utf8"
2222

2323
"ambient-code-backend/git"
24+
"ambient-code-backend/gitlab"
2425
"ambient-code-backend/pathutil"
2526
"ambient-code-backend/types"
2627

@@ -1368,7 +1369,7 @@ func MintSessionGitHubToken(c *gin.Context) {
13681369
// Get GitHub token (GitHub App or PAT fallback via project runner secret)
13691370
tokenStr, err := GetGitHubToken(c.Request.Context(), K8sClient, DynamicClient, project, userID)
13701371
if err != nil {
1371-
log.Printf("Failed to get GitHub token for project %s: %v", project, err)
1372+
log.Printf("Failed to get GitHub token for project %s: %s", project, gitlab.SanitizeErrorMessage(err))
13721373
c.JSON(http.StatusBadGateway, gin.H{"error": "Failed to retrieve GitHub token"})
13731374
return
13741375
}

factory.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Factory Configuration
2+
<!-- This file configures the Remote Factory for your project. -->
3+
<!-- The factory reads this during Init mode and generates .factory/config.json from it. -->
4+
<!-- Fill in each section below. -->
5+
6+
## Goal
7+
<!-- A single sentence describing what this project should achieve. -->
8+
9+
Kubernetes-native AI automation platform that orchestrates agentic sessions through containerized microservices (Go backend/operator, NextJS frontend, Python runner).
10+
11+
## Scope
12+
13+
### Modifiable
14+
<!-- Files and directories the factory is allowed to create or edit. -->
15+
<!-- One path per line. Glob patterns are supported. -->
16+
17+
- components/backend/**/*.go
18+
- components/operator/**/*.go
19+
- components/frontend/src/**/*.ts
20+
- components/frontend/src/**/*.tsx
21+
- components/runners/ambient-runner/**/*.py
22+
- components/ambient-cli/**/*.go
23+
- components/public-api/**/*.go
24+
- components/ambient-api-server/**/*.go
25+
- components/ambient-sdk/**/*.go
26+
- components/ambient-sdk/**/*.py
27+
28+
### Read-only
29+
<!-- Files the factory may read but must never modify. -->
30+
31+
- CLAUDE.md
32+
- README.md
33+
- components/manifests/**/*
34+
- eval/**/*
35+
36+
## Guards
37+
<!-- Rules the factory must never violate. Checked before every commit. -->
38+
39+
- Do not delete or overwrite existing tests
40+
- Do not modify files outside the declared scope
41+
- Do not introduce secrets or credentials into the repository
42+
- All user-facing API ops must use GetK8sClientsForRequest(c), never the backend service account
43+
- No tokens in logs/errors/responses — use len(token) for logging
44+
- No panic() in production Go code — return fmt.Errorf with context
45+
- No any types in frontend TypeScript
46+
47+
## Eval
48+
49+
### Command
50+
<!-- The shell command the factory runs to score a change. -->
51+
<!-- It must output JSON to stdout matching the EvalResult format. -->
52+
53+
```bash
54+
python eval/score.py
55+
```
56+
57+
### Threshold
58+
<!-- Minimum composite score (0.0-1.0) required to keep a change. -->
59+
60+
0.8
61+
62+
## Target Branch
63+
<!-- Branch that experiment PRs target. Default: main -->
64+
<!-- Set to a different branch (e.g. factory/dev) to stage factory changes before merging to main -->
65+
66+
main
67+
68+
## Project Eval
69+
<!-- No project-specific eval dimensions -->
70+
71+
## Eval Weights
72+
- hygiene: 0.50
73+
- growth: 0.50
74+
75+
## Smoke Test
76+
<!-- Optional shell command that must pass before any change is kept. -->
77+
<!-- If configured, this runs as part of `factory precheck` — failure = mandatory revert. -->
78+
<!-- Use for e2e verification: hit an endpoint, run a CLI command, check a process starts. -->
79+
<!-- Example:
80+
```bash
81+
curl -sf http://localhost:8000/health
82+
```
83+
-->
84+
85+
## Constraints
86+
<!-- Soft rules that guide behavior but don't block commits. -->
87+
88+
- Prefer small, incremental changes over large rewrites
89+
- Each change should be accompanied by at least one test
90+
- Follow the existing code style and conventions
91+
- Use conventional commits (squashed on merge to main)
92+
- OwnerReferences on all K8s child resources
93+
94+
## Research Target
95+
<!-- Not a research project -->
96+
97+
## Mutable Surfaces
98+
<!-- Files the Builder is allowed to modify during research experiments. -->
99+
<!-- One glob pattern per line. Only used in research mode. -->
100+
<!-- Example:
101+
- src/**/*.py
102+
- config/*.yaml
103+
-->
104+
105+
## Fixed Surfaces
106+
<!-- Ground truth files, test data, eval infrastructure. -->
107+
<!-- These files are fingerprinted for leakage detection and MUST NOT be modified. -->
108+
<!-- One glob pattern per line. Only used in research mode. -->
109+
<!-- Example:
110+
- tests/gold/*.json
111+
- eval/**/*.py
112+
- data/benchmark/*.jsonl
113+
-->
114+
115+
## Research Constraints
116+
<!-- Additional rules for the research loop. Only used in research mode. -->
117+
<!-- Example:
118+
- Do not use GPT-4 (cost constraint)
119+
- Each experiment must complete within 30 minutes
120+
-->
121+
122+
## Cost Budget
123+
<!-- Per-cycle or total budget constraints for research experiments. -->
124+
<!-- Example: $5/cycle, $50 total -->

0 commit comments

Comments
 (0)