@fulmenhq/tsfulmen 0.1.9 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +90 -0
- package/README.md +130 -4
- package/config/crucible-ts/devsecops/secrets/v1.0.0/defaults.yaml +181 -62
- package/config/crucible-ts/taxonomy/metrics.yaml +60 -1
- package/dist/appidentity/index.js +7 -1
- package/dist/appidentity/index.js.map +1 -1
- package/dist/config/index.js +7 -1
- package/dist/config/index.js.map +1 -1
- package/dist/crucible/index.js +7 -1
- package/dist/crucible/index.js.map +1 -1
- package/dist/errors/index.js +7 -1
- package/dist/errors/index.js.map +1 -1
- package/dist/foundry/index.js +7 -1
- package/dist/foundry/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/{logger-JU2jYitA.d.ts → logger-Eycya5Mz.d.ts} +1 -0
- package/dist/logging/index.d.ts +77 -4
- package/dist/logging/index.js +214 -62
- package/dist/logging/index.js.map +1 -1
- package/dist/pathfinder/index.d.ts +2 -2
- package/dist/pathfinder/index.js +7 -1
- package/dist/pathfinder/index.js.map +1 -1
- package/dist/{registry-n88udrCm.d.ts → registry-_yEKhTTl.d.ts} +3 -2
- package/dist/schema/index.js +7 -1
- package/dist/schema/index.js.map +1 -1
- package/dist/telemetry/index.d.ts +2 -2
- package/dist/telemetry/index.js +46 -3
- package/dist/telemetry/index.js.map +1 -1
- package/package.json +4 -4
- package/schemas/crucible-ts/devsecops/secrets/v1.0.0/secrets.schema.json +247 -30
- package/schemas/crucible-ts/observability/logging/v1.0.0/logger-config.schema.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,96 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
11
|
|
|
12
|
+
- **HTTP Server Metrics** (`@fulmenhq/tsfulmen/telemetry/http`) - Type-safe HTTP instrumentation with Crucible v0.2.18 taxonomy
|
|
13
|
+
- **Core Helpers**:
|
|
14
|
+
- `recordHttpRequest()` - Records all 5 HTTP metrics with automatic unit conversion (ms → seconds)
|
|
15
|
+
- `trackActiveRequest()` - Active requests gauge management with cleanup
|
|
16
|
+
- AppIdentity integration for automatic service label defaults
|
|
17
|
+
- **Framework Middleware**:
|
|
18
|
+
- `createHttpMetricsMiddleware()` - Express/Connect-compatible middleware
|
|
19
|
+
- `createFastifyMetricsPlugin()` - Fastify plugin with hooks
|
|
20
|
+
- `createBunMetricsHandler()` - Bun.serve fetch handler wrapper
|
|
21
|
+
- **Metrics Emitted** (Crucible v0.2.18):
|
|
22
|
+
- `http_requests_total` - Counter with method/route/status/service labels
|
|
23
|
+
- `http_request_duration_seconds` - Histogram with automatic ms → seconds conversion
|
|
24
|
+
- `http_request_size_bytes` - Optional request size histogram
|
|
25
|
+
- `http_response_size_bytes` - Optional response size histogram
|
|
26
|
+
- `http_active_requests` - Active requests gauge
|
|
27
|
+
- **Features**:
|
|
28
|
+
- Configurable route normalizers (prevents cardinality explosion)
|
|
29
|
+
- Optional body size tracking (performance-conscious, disabled by default)
|
|
30
|
+
- Custom method/status extractors for framework flexibility
|
|
31
|
+
- No unsafe TypeScript casts, full type safety
|
|
32
|
+
- **Documentation**:
|
|
33
|
+
- Comprehensive HTTP metrics guide with framework examples
|
|
34
|
+
- Troubleshooting section (6+ common issues with solutions)
|
|
35
|
+
- Production recommendations and best practices
|
|
36
|
+
- Framework integration notes (Express, Fastify, Bun, Node.js HTTP)
|
|
37
|
+
- **Test Coverage**: 40+ tests (100% coverage of helpers module)
|
|
38
|
+
- **Quality**: All tests passing, typecheck clean, lint clean
|
|
39
|
+
|
|
40
|
+
- **Logging Middleware & Secure Redaction** (`@fulmenhq/tsfulmen/logging`) - STRUCTURED profile middleware pipeline with secure-by-default redaction
|
|
41
|
+
- **Middleware Pipeline Support**:
|
|
42
|
+
- Middleware execution for STRUCTURED and ENTERPRISE profiles
|
|
43
|
+
- Child loggers inherit parent middleware chain and bindings
|
|
44
|
+
- Severity adjustment support (middleware can modify event severity)
|
|
45
|
+
- Middleware chain execution before Pino emission
|
|
46
|
+
- **Built-in Middleware**:
|
|
47
|
+
- `RedactSecretsMiddleware` - Enhanced with gofulmen-aligned patterns and field names
|
|
48
|
+
- `AddFieldsMiddleware` - Inject context fields into log events
|
|
49
|
+
- `TransformMiddleware` - Custom event transformations
|
|
50
|
+
- **Helper Function**:
|
|
51
|
+
- `createStructuredLoggerWithRedaction()` - Secure-by-default structured logger
|
|
52
|
+
- Default redaction patterns: SECRET\_*, *TOKEN*, *KEY\*, Base64 blobs, emails, credit cards
|
|
53
|
+
- Default field names (case-insensitive): password, token, apiKey, authorization, secret, cardNumber, cvv, ssn
|
|
54
|
+
- Customization options: customPatterns, customFields, useDefaultPatterns (opt-out)
|
|
55
|
+
- File output support with redaction enabled
|
|
56
|
+
- **Security Model**:
|
|
57
|
+
- Redaction enabled by default when using helper function
|
|
58
|
+
- Gofulmen-aligned patterns for cross-language consistency
|
|
59
|
+
- Case-insensitive field matching (O(1) lookup)
|
|
60
|
+
- Pattern scanning with 10KB threshold optimization
|
|
61
|
+
- **Performance**:
|
|
62
|
+
- Pattern scanning skips strings >10KB to avoid performance degradation
|
|
63
|
+
- Field-based redaction (O(1)) always applies
|
|
64
|
+
- Minimal middleware overhead (<5% for typical events)
|
|
65
|
+
- Pre-compiled regex patterns and lowercase field maps
|
|
66
|
+
- **Documentation**:
|
|
67
|
+
- Comprehensive logging README (789 lines) with 35+ code examples
|
|
68
|
+
- Main README Progressive Logging section with before/after examples
|
|
69
|
+
- API reference for all middleware types and helper functions
|
|
70
|
+
- Troubleshooting guide with 4 common scenarios
|
|
71
|
+
- Migration guide from simple to structured to secure logging
|
|
72
|
+
- **Test Coverage**: 12 new integration tests (121 total logging tests)
|
|
73
|
+
- **Quality**: All tests passing (1749 tests), typecheck clean, fully documented
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## [0.1.10] - 2025-11-17
|
|
78
|
+
|
|
79
|
+
### Fixed
|
|
80
|
+
|
|
81
|
+
- **Critical: Signal catalog loading in installed packages** - Fixed path resolution bug that prevented signals catalog from loading when package was installed via npm. The bundled code in `dist/foundry/index.js` was using incorrect relative paths (`../../../config` instead of `../../config`) due to tsup bundling behavior. Added runtime path detection to handle both development (source files) and production (bundled files) contexts.
|
|
82
|
+
- **Pre-publish verification** - Added `scripts/verify-local-install.ts` and `make verify-local-install` target to catch path resolution bugs before publishing. This script packs the package locally, installs it to a temp directory, and tests catalog loading in the installed context.
|
|
83
|
+
|
|
84
|
+
### Added
|
|
85
|
+
|
|
86
|
+
- Runtime path detection in signals catalog loader (src/foundry/signals/catalog.ts:23-30)
|
|
87
|
+
- Pre-publish integration test (scripts/verify-local-install.ts)
|
|
88
|
+
- Makefile target `verify-local-install` for pre-publish verification
|
|
89
|
+
|
|
90
|
+
### Changed
|
|
91
|
+
|
|
92
|
+
- Signals catalog path resolution now detects whether running from source (`src/`) or dist (`dist/`) and adjusts paths accordingly
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## [0.1.9] - 2025-11-16 [DEPRECATED - Non-functional]
|
|
97
|
+
|
|
98
|
+
**⚠️ DO NOT USE**: This version has a critical bug where catalog loading fails in installed packages. Use v0.1.10 or later.
|
|
99
|
+
|
|
100
|
+
### Added
|
|
101
|
+
|
|
12
102
|
- **Fulpack Module** (`@fulmenhq/tsfulmen/fulpack`) - Security-first archive operations for TAR, TAR.GZ, ZIP, and GZIP formats
|
|
13
103
|
- **Five Canonical Operations**:
|
|
14
104
|
- `create()` - Create archives from files/directories with configurable compression
|
package/README.md
CHANGED
|
@@ -9,19 +9,20 @@ TypeScript Fulmen helper library for enterprise-scale development.
|
|
|
9
9
|
## Status
|
|
10
10
|
|
|
11
11
|
**Lifecycle Phase:** `alpha` (see [`LIFECYCLE_PHASE`](LIFECYCLE_PHASE))
|
|
12
|
-
**Development Status:**
|
|
13
|
-
**Test Coverage:**
|
|
12
|
+
**Development Status:** 🚧 v0.1.11 - HTTP server metrics, logging middleware with secure redaction
|
|
13
|
+
**Test Coverage:** 1749 tests passing (100% pass rate)
|
|
14
14
|
|
|
15
|
-
TSFulmen v0.1.
|
|
15
|
+
TSFulmen v0.1.11 adds HTTP server metrics with Crucible v0.2.18 taxonomy (Express/Fastify/Bun middleware) and logging middleware pipeline with secure-by-default redaction (gofulmen-aligned patterns). See [TSFulmen Overview](docs/tsfulmen_overview.md) for roadmap.
|
|
16
16
|
|
|
17
17
|
## Features
|
|
18
18
|
|
|
19
19
|
- ✅ **Error Handling** - Schema-backed FulmenError with severity levels (43 tests)
|
|
20
20
|
- ✅ **Telemetry & Metrics** - Counter/gauge/histogram with OTLP export (85 tests)
|
|
21
21
|
- ✅ **Telemetry Instrumentation** - Metrics in config, schema, crucible modules (24 tests)
|
|
22
|
+
- ✅ **HTTP Server Metrics** - Type-safe HTTP instrumentation with Express/Fastify/Bun middleware (40+ tests)
|
|
22
23
|
- ✅ **FulHash** - Fast hashing with XXH3-128 and SHA-256, 22x faster small inputs (157 tests)
|
|
23
24
|
- ✅ **Fulpack** - Archive operations (TAR, TAR.GZ, ZIP, GZIP) with security-first design (20 tests)
|
|
24
|
-
- ✅ **Progressive Logging** - Policy enforcement with Pino profiles (
|
|
25
|
+
- ✅ **Progressive Logging** - Policy enforcement with Pino profiles, middleware pipeline, secure redaction (121 tests)
|
|
25
26
|
- ✅ **Crucible Shim** - Typed access to synced schemas, docs, and config defaults (96 tests)
|
|
26
27
|
- ✅ **DocScribe** - Document processing with frontmatter parsing (50+ tests)
|
|
27
28
|
- ✅ **Config Path API** - XDG-compliant configuration directory resolution (26 tests)
|
|
@@ -237,6 +238,131 @@ await metrics.flush({
|
|
|
237
238
|
});
|
|
238
239
|
```
|
|
239
240
|
|
|
241
|
+
### HTTP Server Metrics
|
|
242
|
+
|
|
243
|
+
Type-safe HTTP instrumentation with automatic route normalization and cardinality protection:
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
import {
|
|
247
|
+
recordHttpRequest,
|
|
248
|
+
trackActiveRequest,
|
|
249
|
+
createHttpMetricsMiddleware,
|
|
250
|
+
} from "@fulmenhq/tsfulmen/telemetry/http";
|
|
251
|
+
|
|
252
|
+
// Express middleware (automatic instrumentation)
|
|
253
|
+
app.use(
|
|
254
|
+
createHttpMetricsMiddleware({
|
|
255
|
+
serviceName: "api-server",
|
|
256
|
+
routeNormalizer: (req) => req.route?.path || normalizeRoute(req.path),
|
|
257
|
+
trackBodySizes: true, // Optional: track request/response sizes
|
|
258
|
+
}),
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
// Manual instrumentation
|
|
262
|
+
const start = performance.now();
|
|
263
|
+
const release = trackActiveRequest("api-server");
|
|
264
|
+
try {
|
|
265
|
+
await handleRequest();
|
|
266
|
+
recordHttpRequest({
|
|
267
|
+
method: "GET",
|
|
268
|
+
route: "/users/:id", // Pre-normalized route
|
|
269
|
+
status: 200,
|
|
270
|
+
durationMs: performance.now() - start,
|
|
271
|
+
requestBytes: 512,
|
|
272
|
+
responseBytes: 2048,
|
|
273
|
+
});
|
|
274
|
+
} finally {
|
|
275
|
+
release();
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Metrics emitted** (Crucible v0.2.18 taxonomy):
|
|
280
|
+
|
|
281
|
+
- `http_requests_total` - Request counter with method/route/status/service labels
|
|
282
|
+
- `http_request_duration_seconds` - Duration histogram (auto-converts ms → seconds)
|
|
283
|
+
- `http_request_size_bytes` - Request size histogram (optional)
|
|
284
|
+
- `http_response_size_bytes` - Response size histogram (optional)
|
|
285
|
+
- `http_active_requests` - Active requests gauge
|
|
286
|
+
|
|
287
|
+
**⚠️ Critical**: Routes must be normalized to prevent cardinality explosion. Use `normalizeRoute()` or framework route templates. See [HTTP Metrics Guide](src/telemetry/http/README.md).
|
|
288
|
+
|
|
289
|
+
**Framework support**: Express, Fastify, Bun.serve, Node.js HTTP
|
|
290
|
+
|
|
291
|
+
### Progressive Logging
|
|
292
|
+
|
|
293
|
+
TSFulmen provides profile-based logging from simple CLI tools to enterprise observability with secure redaction middleware.
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
import {
|
|
297
|
+
createSimpleLogger,
|
|
298
|
+
createStructuredLogger,
|
|
299
|
+
createStructuredLoggerWithRedaction,
|
|
300
|
+
} from "@fulmenhq/tsfulmen/logging";
|
|
301
|
+
|
|
302
|
+
// Simple: Human-readable for CLI tools
|
|
303
|
+
const cli = createSimpleLogger("mycli");
|
|
304
|
+
cli.info("Processing file", { path: "/data/input.csv" });
|
|
305
|
+
|
|
306
|
+
// Structured: JSON output for APIs
|
|
307
|
+
const api = createStructuredLogger("api-server");
|
|
308
|
+
api.info("Request processed", { requestId: "req-456", duration: 42 });
|
|
309
|
+
|
|
310
|
+
// Structured + Redaction: Secure by default
|
|
311
|
+
const secure = createStructuredLoggerWithRedaction("auth-service");
|
|
312
|
+
secure.info("User login", {
|
|
313
|
+
userId: "user-123",
|
|
314
|
+
email: "user@example.com", // ← Automatically redacted
|
|
315
|
+
password: "secret123", // ← Automatically redacted
|
|
316
|
+
apiKey: "sk_live_1234567890", // ← Automatically redacted
|
|
317
|
+
});
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**Output** (with redaction):
|
|
321
|
+
|
|
322
|
+
```json
|
|
323
|
+
{
|
|
324
|
+
"severity": "INFO",
|
|
325
|
+
"timestamp": "2025-11-18T12:00:00.000Z",
|
|
326
|
+
"service": "auth-service",
|
|
327
|
+
"message": "User login",
|
|
328
|
+
"userId": "user-123",
|
|
329
|
+
"email": "[REDACTED]",
|
|
330
|
+
"password": "[REDACTED]",
|
|
331
|
+
"apiKey": "[REDACTED]"
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**Security Model**: `createStructuredLoggerWithRedaction()` enables redaction by default with gofulmen-aligned patterns for common secrets (passwords, tokens, API keys, emails, credit cards).
|
|
336
|
+
|
|
337
|
+
**Performance**: Pattern scanning automatically skips strings larger than 10KB to avoid performance impact on large payloads. Field-based redaction (O(1) lookup) always applies.
|
|
338
|
+
|
|
339
|
+
**Customization**:
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
// Add organization-specific patterns
|
|
343
|
+
const logger = createStructuredLoggerWithRedaction("api-server", {
|
|
344
|
+
customPatterns: [/INTERNAL_ID_\d+/g, /CUST_[A-Z0-9]{10}/g],
|
|
345
|
+
customFields: ["internalKey", "customerSecret"],
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// Opt-out of defaults for full control
|
|
349
|
+
const customLogger = createStructuredLoggerWithRedaction("api-server", {
|
|
350
|
+
useDefaultPatterns: false,
|
|
351
|
+
customPatterns: [/MY_SECRET/g],
|
|
352
|
+
});
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Child Loggers**: Child loggers inherit middleware and bindings from parent.
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
const parent = createStructuredLoggerWithRedaction("api-server");
|
|
359
|
+
const child = parent.child({ requestId: "req-789" });
|
|
360
|
+
|
|
361
|
+
child.info("Processing", { password: "secret" }); // ← Still redacted!
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
See [Logging README](src/logging/README.md) for complete documentation including middleware, profiles, and policy enforcement.
|
|
365
|
+
|
|
240
366
|
### Config Path API
|
|
241
367
|
|
|
242
368
|
```typescript
|
|
@@ -8,63 +8,148 @@
|
|
|
8
8
|
# WARNING: This is a SAMPLE file with anonymized/fake secrets for demonstration.
|
|
9
9
|
# DO NOT commit real secrets to version control in plaintext.
|
|
10
10
|
# Use encryption (fulsecrets encrypt) before committing production secrets.
|
|
11
|
-
|
|
12
|
-
# Example 1: Development Environment (Plaintext)
|
|
11
|
+
# Example 1: Minimal Development Environment (Plaintext)
|
|
13
12
|
# Use case: Local development with non-sensitive test credentials
|
|
14
13
|
# Policy: allow_plain_secrets = true (default)
|
|
15
|
-
|
|
14
|
+
schema_version: v1.0.0
|
|
15
|
+
env_prefix: APP_
|
|
16
16
|
projects:
|
|
17
17
|
- project_slug: myapp-dev
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
18
|
+
credentials:
|
|
19
|
+
DATABASE_URL:
|
|
20
|
+
type: password
|
|
21
|
+
value: postgres://localhost:5432/myapp_dev
|
|
22
|
+
REDIS_URL:
|
|
23
|
+
type: password
|
|
24
|
+
value: redis://localhost:6379/0
|
|
25
|
+
API_KEY:
|
|
26
|
+
type: api_key
|
|
27
|
+
value: dev_key_12345_not_real
|
|
28
|
+
SECRET_TOKEN:
|
|
29
|
+
type: token
|
|
30
|
+
value: dev_secret_abc_not_real
|
|
31
|
+
LOG_LEVEL:
|
|
32
|
+
type: password
|
|
33
|
+
value: debug
|
|
33
34
|
policies:
|
|
34
35
|
allow_plain_secrets: true # OK for development
|
|
35
36
|
|
|
36
|
-
# Example 2:
|
|
37
|
-
# Use case:
|
|
38
|
-
# Pattern:
|
|
37
|
+
# Example 2: Full-Featured Credentials with Metadata & Rotation
|
|
38
|
+
# Use case: Production secrets with lifecycle tracking and rotation policies
|
|
39
|
+
# Pattern: Rich credential objects with type, metadata, rotation
|
|
40
|
+
---
|
|
41
|
+
schema_version: v1.0.0
|
|
42
|
+
description: |
|
|
43
|
+
Production secrets for MyApp platform
|
|
44
|
+
Contact: platform-team@example.com
|
|
45
|
+
Last updated: 2025-11-17
|
|
46
|
+
env_prefix: PROD_
|
|
47
|
+
projects:
|
|
48
|
+
- project_slug: backend_api
|
|
49
|
+
description: Backend API services
|
|
50
|
+
credentials:
|
|
51
|
+
STRIPE_API_KEY:
|
|
52
|
+
type: api_key
|
|
53
|
+
value: sk_live_abc123def456_not_real
|
|
54
|
+
description: Live Stripe API key for payment processing
|
|
55
|
+
metadata:
|
|
56
|
+
created: "2025-01-15T10:00:00Z"
|
|
57
|
+
expires: "2026-01-15T10:00:00Z"
|
|
58
|
+
purpose: payment-processing
|
|
59
|
+
tags:
|
|
60
|
+
- payment
|
|
61
|
+
- critical
|
|
62
|
+
- pci-scope
|
|
63
|
+
owner: payments-team
|
|
64
|
+
rotation:
|
|
65
|
+
interval: 90d
|
|
66
|
+
method: auto
|
|
67
|
+
DATABASE_PASSWORD:
|
|
68
|
+
type: password
|
|
69
|
+
value: super_secure_password_not_real
|
|
70
|
+
description: Primary PostgreSQL database password
|
|
71
|
+
metadata:
|
|
72
|
+
created: "2025-01-01T00:00:00Z"
|
|
73
|
+
expires: "2025-12-31T23:59:59Z"
|
|
74
|
+
purpose: primary-database
|
|
75
|
+
tags:
|
|
76
|
+
- database
|
|
77
|
+
- critical
|
|
78
|
+
owner: platform-team
|
|
79
|
+
rotation:
|
|
80
|
+
interval: 30d
|
|
81
|
+
method: manual
|
|
82
|
+
JWT_SECRET:
|
|
83
|
+
type: token
|
|
84
|
+
value: bearer_token_abc123_not_real
|
|
85
|
+
description: JWT signing secret for authentication
|
|
86
|
+
metadata:
|
|
87
|
+
purpose: authentication
|
|
88
|
+
tags:
|
|
89
|
+
- auth
|
|
90
|
+
- critical
|
|
91
|
+
REDIS_PASSWORD:
|
|
92
|
+
type: password
|
|
93
|
+
value: redis_password_xyz789_not_real
|
|
94
|
+
description: Redis cache password
|
|
95
|
+
|
|
96
|
+
# Example 3: Multi-Project with External References
|
|
97
|
+
# Use case: Monorepo with multiple services, some credentials from Vault
|
|
98
|
+
# Pattern: Mix of inline values and external references (vault://, aws-secrets://)
|
|
39
99
|
---
|
|
40
100
|
schema_version: v1.0.0
|
|
41
101
|
projects:
|
|
42
102
|
- project_slug: api-staging
|
|
43
|
-
|
|
44
|
-
DATABASE_URL:
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
103
|
+
credentials:
|
|
104
|
+
DATABASE_URL:
|
|
105
|
+
type: password
|
|
106
|
+
ref: vault://secrets/staging/db-url
|
|
107
|
+
description: Database URL from HashiCorp Vault
|
|
108
|
+
REDIS_URL:
|
|
109
|
+
type: password
|
|
110
|
+
value: redis://staging-cache.internal:6379
|
|
111
|
+
JWT_SECRET:
|
|
112
|
+
type: token
|
|
113
|
+
value: staging_jwt_secret_abc123_not_real
|
|
114
|
+
API_KEY:
|
|
115
|
+
type: api_key
|
|
116
|
+
value: sk_staging_api_key_not_real
|
|
117
|
+
SENTRY_DSN:
|
|
118
|
+
type: password
|
|
119
|
+
value: https://fake@sentry.io/staging
|
|
49
120
|
- project_slug: worker-staging
|
|
50
|
-
|
|
51
|
-
DATABASE_URL:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
SENTRY_DSN:
|
|
121
|
+
credentials:
|
|
122
|
+
DATABASE_URL:
|
|
123
|
+
type: password
|
|
124
|
+
ref: vault://secrets/staging/db-url # Shared reference
|
|
125
|
+
QUEUE_URL:
|
|
126
|
+
type: password
|
|
127
|
+
value: amqp://staging-queue.internal:5672
|
|
128
|
+
WORKER_TOKEN:
|
|
129
|
+
type: token
|
|
130
|
+
value: staging_worker_token_xyz789_not_real
|
|
131
|
+
SENTRY_DSN:
|
|
132
|
+
type: password
|
|
133
|
+
value: https://fake@sentry.io/staging
|
|
134
|
+
- project_slug: frontend_staging
|
|
135
|
+
env_prefix: VITE_ # Override global prefix for frontend
|
|
136
|
+
credentials:
|
|
137
|
+
API_URL:
|
|
138
|
+
type: password
|
|
139
|
+
value: https://api-staging.example.com
|
|
140
|
+
ANALYTICS_KEY:
|
|
141
|
+
type: api_key
|
|
142
|
+
value: staging_analytics_key_not_real
|
|
143
|
+
SENTRY_DSN:
|
|
144
|
+
type: password
|
|
145
|
+
value: https://fake@sentry.io/staging
|
|
61
146
|
|
|
62
|
-
# Example
|
|
147
|
+
# Example 4: Production Environment (Encrypted - GPG)
|
|
63
148
|
# Use case: Production secrets encrypted with GPG for team access
|
|
64
149
|
# Policy: allow_plain_secrets = false (enforce encryption)
|
|
65
150
|
#
|
|
66
151
|
# How to create:
|
|
67
|
-
# 1. Create plaintext file with real secrets
|
|
152
|
+
# 1. Create plaintext file with real secrets (using credential objects)
|
|
68
153
|
# 2. Run: fulsecrets encrypt secrets.yaml --gpg-key team@example.com
|
|
69
154
|
# 3. Commit encrypted file to version control
|
|
70
155
|
#
|
|
@@ -82,10 +167,18 @@ encryption:
|
|
|
82
167
|
# When decrypted, it contains:
|
|
83
168
|
# projects:
|
|
84
169
|
# - project_slug: myapp-prod
|
|
85
|
-
#
|
|
86
|
-
# DATABASE_URL:
|
|
87
|
-
#
|
|
88
|
-
#
|
|
170
|
+
# credentials:
|
|
171
|
+
# DATABASE_URL:
|
|
172
|
+
# type: password
|
|
173
|
+
# value: postgres://prod-db.example.com:5432/myapp
|
|
174
|
+
# API_KEY:
|
|
175
|
+
# type: api_key
|
|
176
|
+
# value: sk_live_real_production_key
|
|
177
|
+
# metadata:
|
|
178
|
+
# expires: "2026-01-01T00:00:00Z"
|
|
179
|
+
# rotation:
|
|
180
|
+
# interval: 90d
|
|
181
|
+
# method: auto
|
|
89
182
|
ciphertext: |
|
|
90
183
|
-----BEGIN PGP MESSAGE-----
|
|
91
184
|
|
|
@@ -95,7 +188,7 @@ ciphertext: |
|
|
|
95
188
|
policies:
|
|
96
189
|
allow_plain_secrets: false # Enforce encryption for production
|
|
97
190
|
|
|
98
|
-
# Example
|
|
191
|
+
# Example 5: Production Environment (Encrypted - age)
|
|
99
192
|
# Use case: Modern encryption with age instead of GPG
|
|
100
193
|
# Pattern: Same as GPG but using age public/private key pairs
|
|
101
194
|
#
|
|
@@ -120,7 +213,7 @@ ciphertext: |
|
|
|
120
213
|
policies:
|
|
121
214
|
allow_plain_secrets: false
|
|
122
215
|
|
|
123
|
-
# Example
|
|
216
|
+
# Example 6: Passphrase-Based Encryption (Simplest)
|
|
124
217
|
# Use case: Solo developer or small team with shared passphrase
|
|
125
218
|
# Pattern: No key management needed, just a strong passphrase
|
|
126
219
|
#
|
|
@@ -151,44 +244,70 @@ policies:
|
|
|
151
244
|
|
|
152
245
|
# Best Practices & Security Notes:
|
|
153
246
|
#
|
|
154
|
-
# 1.
|
|
247
|
+
# 1. Credential Types:
|
|
248
|
+
# - api_key: External service keys (Stripe, GitHub, AWS) - masked as "sk_live_...xyz"
|
|
249
|
+
# - token: Auth tokens, JWTs, bearer tokens - masked as "...1234"
|
|
250
|
+
# - password: Passwords, passphrases, DB URLs - fully redacted "***REDACTED***"
|
|
251
|
+
#
|
|
252
|
+
# 2. Value vs Ref:
|
|
253
|
+
# - Use 'value' for inline secrets (development, small deployments)
|
|
254
|
+
# - Use 'ref' for external secret managers (Vault, AWS Secrets Manager)
|
|
255
|
+
# - Never include both 'value' and 'ref' (mutually exclusive)
|
|
256
|
+
#
|
|
257
|
+
# 3. Metadata & Rotation:
|
|
258
|
+
# - Add 'metadata.expires' for time-based rotation tracking
|
|
259
|
+
# - Use 'rotation.interval' to document rotation policy (30d, 90d, 180d)
|
|
260
|
+
# - Set 'rotation.method: auto' for automated rotation, 'manual' otherwise
|
|
261
|
+
# - Tag critical credentials with 'tags: [critical]' for monitoring
|
|
262
|
+
#
|
|
263
|
+
# 4. NEVER commit plaintext production secrets to version control:
|
|
155
264
|
# - Always encrypt production files before git add
|
|
156
265
|
# - Use .gitignore for *-plain.yaml, *-decrypted.yaml patterns
|
|
266
|
+
# - Run 'git secrets --scan' or similar tools to prevent leaks
|
|
157
267
|
#
|
|
158
|
-
#
|
|
268
|
+
# 5. Policy enforcement:
|
|
159
269
|
# - Set allow_plain_secrets: false for staging/production
|
|
160
270
|
# - Keep allow_plain_secrets: true for local development
|
|
161
271
|
# - Use fulsecrets validate --strict to catch violations
|
|
162
272
|
#
|
|
163
|
-
#
|
|
273
|
+
# 6. Key management:
|
|
164
274
|
# - GPG: Good for teams with existing GPG infrastructure
|
|
165
275
|
# - Age: Modern alternative, simpler key management
|
|
166
276
|
# - Passphrase: Simplest for solo dev, store in password manager
|
|
167
277
|
#
|
|
168
|
-
#
|
|
278
|
+
# 7. CI/CD integration:
|
|
169
279
|
# - Store passphrases/keys in GitHub Secrets / GitLab CI Variables
|
|
170
280
|
# - Use environment variables (FULSECRETS_PASSPHRASE) to avoid prompts
|
|
171
281
|
# - Never echo/print secrets in CI logs
|
|
172
282
|
#
|
|
173
|
-
#
|
|
174
|
-
# -
|
|
283
|
+
# 8. Secret rotation workflow:
|
|
284
|
+
# - Decrypt existing file: fulsecrets decrypt secrets.yaml
|
|
285
|
+
# - Update credential values and metadata.expires timestamps
|
|
286
|
+
# - Re-encrypt with same method: fulsecrets encrypt secrets.yaml
|
|
175
287
|
# - For key rotation: decrypt, re-encrypt with new key
|
|
176
|
-
# - Update encryption.encrypted_at to track rotation
|
|
177
288
|
#
|
|
178
|
-
#
|
|
289
|
+
# 9. Temporary files:
|
|
179
290
|
# - fulsecrets edit uses secure temp files (/dev/shm, 0600 perms)
|
|
180
291
|
# - Manual workflow: always rm plaintext files after encryption
|
|
181
292
|
# - Use shred/srm for sensitive cleanup if available
|
|
182
293
|
#
|
|
183
|
-
#
|
|
184
|
-
#
|
|
185
|
-
#
|
|
186
|
-
#
|
|
294
|
+
# 10. Environment variable naming:
|
|
295
|
+
# - Use UPPER_SNAKE_CASE for credential keys
|
|
296
|
+
# - Add env_prefix for namespacing (APP_, SERVICE_, PROD_, etc.)
|
|
297
|
+
# - Avoid generic names like "KEY" or "TOKEN" (use API_KEY, JWT_TOKEN)
|
|
298
|
+
# - Global env_prefix applies to all projects, can override per-project
|
|
299
|
+
#
|
|
300
|
+
# 11. Project slugs:
|
|
301
|
+
# - Use lowercase alphanumeric + hyphens/underscores
|
|
302
|
+
# - Pattern: service-environment (api-staging, worker-prod)
|
|
303
|
+
# - Or: service_version-env (api_v2-staging, backend_legacy-prod)
|
|
304
|
+
# - Examples: backend-api, frontend_app, worker-staging, my_service-v2
|
|
187
305
|
#
|
|
188
|
-
#
|
|
189
|
-
#
|
|
190
|
-
#
|
|
191
|
-
#
|
|
306
|
+
# 12. Compliance / FIPS mode:
|
|
307
|
+
# - Set allow_plain_secrets: false for compliance
|
|
308
|
+
# - Use GPG with FIPS 140-2 validated crypto if required
|
|
309
|
+
# - Document encryption method in security policy
|
|
310
|
+
# - Track rotation with metadata.expires and rotation.interval
|
|
192
311
|
#
|
|
193
312
|
# Schema Documentation:
|
|
194
313
|
# https://github.com/fulmenhq/crucible/blob/main/docs/standards/devsecops/project-secrets.md
|
|
@@ -44,6 +44,11 @@ $defs:
|
|
|
44
44
|
- fulhash_hash_string_total
|
|
45
45
|
- fulhash_bytes_hashed_total
|
|
46
46
|
- fulhash_operation_ms
|
|
47
|
+
- http_requests_total
|
|
48
|
+
- http_request_duration_seconds
|
|
49
|
+
- http_request_size_bytes
|
|
50
|
+
- http_response_size_bytes
|
|
51
|
+
- http_active_requests
|
|
47
52
|
metricUnit:
|
|
48
53
|
type: string
|
|
49
54
|
enum:
|
|
@@ -70,6 +75,16 @@ properties:
|
|
|
70
75
|
description: Default millisecond buckets used when metric name ends with `_ms`.
|
|
71
76
|
items:
|
|
72
77
|
type: number
|
|
78
|
+
seconds_metrics:
|
|
79
|
+
type: array
|
|
80
|
+
description: Default second buckets used when metric unit is `s` (for HTTP latency and duration metrics).
|
|
81
|
+
items:
|
|
82
|
+
type: number
|
|
83
|
+
bytes_metrics:
|
|
84
|
+
type: array
|
|
85
|
+
description: Default byte buckets used when metric name ends with `_bytes` (for HTTP request/response size metrics).
|
|
86
|
+
items:
|
|
87
|
+
type: number
|
|
73
88
|
additionalProperties: false
|
|
74
89
|
additionalProperties: false
|
|
75
90
|
metrics:
|
|
@@ -93,7 +108,7 @@ required:
|
|
|
93
108
|
- version
|
|
94
109
|
- metrics
|
|
95
110
|
additionalProperties: false
|
|
96
|
-
version: "0.2.
|
|
111
|
+
version: "0.2.18"
|
|
97
112
|
defaults:
|
|
98
113
|
histogram_buckets:
|
|
99
114
|
ms_metrics:
|
|
@@ -106,6 +121,25 @@ defaults:
|
|
|
106
121
|
- 1000
|
|
107
122
|
- 5000
|
|
108
123
|
- 10000
|
|
124
|
+
seconds_metrics:
|
|
125
|
+
- 0.005
|
|
126
|
+
- 0.01
|
|
127
|
+
- 0.025
|
|
128
|
+
- 0.05
|
|
129
|
+
- 0.1
|
|
130
|
+
- 0.25
|
|
131
|
+
- 0.5
|
|
132
|
+
- 1
|
|
133
|
+
- 2.5
|
|
134
|
+
- 5
|
|
135
|
+
- 10
|
|
136
|
+
bytes_metrics:
|
|
137
|
+
- 1024
|
|
138
|
+
- 10240
|
|
139
|
+
- 102400
|
|
140
|
+
- 1048576
|
|
141
|
+
- 10485760
|
|
142
|
+
- 104857600
|
|
109
143
|
metrics:
|
|
110
144
|
- name: schema_validations
|
|
111
145
|
unit: count
|
|
@@ -269,3 +303,28 @@ metrics:
|
|
|
269
303
|
unit: ms
|
|
270
304
|
description: >
|
|
271
305
|
Hash operation latency in milliseconds for all algorithms. Uses ADR-0007 buckets: [1, 5, 10, 50, 100, 500, 1000, 5000, 10000]. Enables performance benchmarking across XXH3-128 and SHA256.
|
|
306
|
+
|
|
307
|
+
- name: http_requests_total
|
|
308
|
+
unit: count
|
|
309
|
+
description: >
|
|
310
|
+
Total HTTP server requests received. Counter metric tracking all HTTP requests by method, route, status, and service. Required labels: method (GET/POST/etc), route (templated path like /users/:id to avoid cardinality), status (HTTP status code), service (service identifier). Optional labels: outcome (2xx/4xx/5xx grouping derived from status). IMPORTANT: Use normalized/templated routes (e.g., /users/:id, not /users/123) to prevent cardinality explosion. Helpers SHOULD provide route normalization utilities.
|
|
311
|
+
|
|
312
|
+
- name: http_request_duration_seconds
|
|
313
|
+
unit: s
|
|
314
|
+
description: >
|
|
315
|
+
HTTP server request duration in seconds. Histogram metric measuring request latency from receipt to response. Uses default seconds buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10]. Required labels: method, route (templated), status, service. Optional labels: outcome. Helpers exposing millisecond APIs MUST document unit conversion (1 second = 1000 ms). Use templated routes to control cardinality.
|
|
316
|
+
|
|
317
|
+
- name: http_request_size_bytes
|
|
318
|
+
unit: bytes
|
|
319
|
+
description: >
|
|
320
|
+
HTTP server request body size in bytes. Histogram metric measuring incoming request payload sizes. Uses default bytes buckets: [1024, 10240, 102400, 1048576, 10485760, 104857600] (1KB to 100MB). Required labels: method, route (templated), service. Enables monitoring payload patterns and capacity planning. Use templated routes to avoid cardinality issues.
|
|
321
|
+
|
|
322
|
+
- name: http_response_size_bytes
|
|
323
|
+
unit: bytes
|
|
324
|
+
description: >
|
|
325
|
+
HTTP server response body size in bytes. Histogram metric measuring outgoing response payload sizes. Uses default bytes buckets: [1024, 10240, 102400, 1048576, 10485760, 104857600] (1KB to 100MB). Required labels: method, route (templated), status, service. Optional labels: outcome. Tracks bandwidth usage and response patterns. Use templated routes to prevent cardinality explosion.
|
|
326
|
+
|
|
327
|
+
- name: http_active_requests
|
|
328
|
+
unit: count
|
|
329
|
+
description: >
|
|
330
|
+
Number of HTTP requests currently being processed. Gauge metric tracking concurrent request load. Required labels: service. Intentionally minimal labels to avoid cardinality. Helps monitor server capacity and saturation. Increment on request start, decrement on completion.
|