Add safe URL construction rules to agent guides

Add a URL and query parameter construction section to
contrib/claude/go-style.md requiring net/url (url.JoinPath,
url.Values, url.Parse) instead of fmt.Sprintf or string
concatenation.

Create contrib/claude/ts-style.md with matching TypeScript
rules requiring URL and URLSearchParams instead of template
literals or string concatenation.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2026-04-24 16:12:24 +02:00
parent 1cc9f011f4
commit f82d76b246
3 changed files with 89 additions and 1 deletions

View File

@@ -4,7 +4,8 @@ Detailed guides for specific subsystems live in `contrib/claude/`:
- [`contrib/claude/make.md`](contrib/claude/make.md) — GNUmakefile targets, codegen, overridable variables
- [`contrib/claude/api-surface.md`](contrib/claude/api-surface.md) — GraphQL / MCP / CLI / n8n sync rules
- [`contrib/claude/go-style.md`](contrib/claude/go-style.md) — Go project deps, style (declarations, calls, imports, errors, naming, logging)
- [`contrib/claude/go-style.md`](contrib/claude/go-style.md) — Go project deps, style (declarations, calls, imports, errors, naming, logging, safe URL construction)
- [`contrib/claude/ts-style.md`](contrib/claude/ts-style.md) — TypeScript style (safe URL construction)
- [`contrib/claude/go-testing.md`](contrib/claude/go-testing.md) — Go test conventions (parallel, require vs assert, naming)
- [`contrib/claude/go-service.md`](contrib/claude/go-service.md) — Go service orchestration (Run, graceful shutdown, crash propagation)
- [`contrib/claude/go-worker.md`](contrib/claude/go-worker.md) — Go worker pattern (poll-based, bounded concurrency, FOR UPDATE SKIP LOCKED)

View File

@@ -175,6 +175,61 @@ type ctxKey struct{ name string }
var trustCenterIDKey = &ctxKey{name: "trust_center_id"}
```
## URL and query parameter construction
**Never** build URLs with `fmt.Sprintf`, string concatenation, or any form of string formatting. Always use the `net/url` package to construct URLs safely.
- Use `url.URL` struct to build full URLs (scheme, host, path, query).
- Use `url.Values` to build query parameters, then call `.Encode()`.
- Use `url.QueryEscape` or `url.PathEscape` when embedding a single value into a known-safe base.
- Use the `pkg/baseurl.URLBuilder` when constructing URLs from configured base URLs.
```go
// Bad — fmt.Sprintf
endpoint := fmt.Sprintf("https://api.example.com/users/%s?active=%t", userID, active)
// Bad — string concatenation
endpoint := "https://api.example.com/orgs/" + orgID + "/members"
// Good — url.JoinPath escapes each segment and sets Path + RawPath
u, err := url.JoinPath("https://api.example.com", "users", userID)
if err != nil {
return fmt.Errorf("cannot build URL: %w", err)
}
parsed, err := url.Parse(u)
if err != nil {
return fmt.Errorf("cannot parse URL: %w", err)
}
q := parsed.Query()
q.Set("active", strconv.FormatBool(active))
parsed.RawQuery = q.Encode()
// Good — URLBuilder from pkg/baseurl
u, err := baseURL.URL("/users", userID).
Query("active", strconv.FormatBool(active)).
Build()
```
The same rule applies to query parameters specifically: never concatenate `"?key=" + val + "&other=" + val2`. Always use `url.Values` and assign via `RawQuery`:
```go
// Bad
raw := baseEndpoint + "?domain=" + domain + "&limit=100"
// Good
u, err := url.Parse(baseEndpoint)
if err != nil {
return fmt.Errorf("cannot parse endpoint: %w", err)
}
q := u.Query()
q.Set("domain", domain)
q.Set("limit", "100")
u.RawQuery = q.Encode()
```
## Logging
`go.gearno.de/kit/log` — named, context-aware structured logging with typed fields. **Never log PII, PHI, or other sensitive data** (e.g. emails, names, passwords, tokens, health records). Log opaque identifiers (IDs, request IDs) instead. See [`contrib/claude/logging.md`](logging.md) for the full guide (allowed/forbidden data, field helpers, wiring patterns).

View File

@@ -0,0 +1,32 @@
# TypeScript Style
## URL and query parameter construction
**Never** build URLs with template literals, string concatenation, or string formatting. Always use the `URL` and `URLSearchParams` APIs.
- Use `new URL()` to construct or parse full URLs.
- Use `URLSearchParams` to build query strings.
- Use `.pathname`, `.searchParams`, and other `URL` properties to modify parts of a URL safely.
- Use `encodeURIComponent` for dynamic path segments.
```typescript
// Bad — template literal
const endpoint = `https://api.example.com/users/${userId}?active=${active}`;
// Bad — string concatenation
const endpoint = "https://api.example.com/orgs/" + orgId + "/members";
// Bad — query params via string concat
const qs = "?domain=" + domain + "&limit=100";
// Good — URL object
const url = new URL("https://api.example.com");
url.pathname = `/users/${encodeURIComponent(userId)}`;
url.searchParams.set("active", String(active));
// Good — URLSearchParams for query strings
const params = new URLSearchParams();
params.set("domain", domain);
params.set("limit", "100");
const qs = params.toString();
```