@sentinel-atl/registry 0.3.0
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/README.md +102 -0
- package/dist/badge.d.ts +37 -0
- package/dist/badge.d.ts.map +1 -0
- package/dist/badge.js +114 -0
- package/dist/badge.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +66 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +58 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +347 -0
- package/dist/server.js.map +1 -0
- package/dist/store.d.ts +104 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +177 -0
- package/dist/store.js.map +1 -0
- package/package.json +47 -0
- package/src/__tests__/registry.test.ts +304 -0
- package/src/badge.ts +139 -0
- package/src/cli.ts +74 -0
- package/src/index.ts +31 -0
- package/src/server.ts +407 -0
- package/src/store.ts +267 -0
- package/tsconfig.json +9 -0
package/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# @sentinel-atl/registry
|
|
2
|
+
|
|
3
|
+
Trust Registry API — publish, query, and verify Sentinel Trust Certificates.
|
|
4
|
+
|
|
5
|
+
Provides an HTTP server for storing and querying STCs (Sentinel Trust Certificates) with SVG trust badges, optional persistent storage, API key auth, CORS, TLS, and rate limiting.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @sentinel-atl/registry
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
### CLI
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx sentinel-registry # Start on default port 3200
|
|
19
|
+
npx sentinel-registry --port 8080 # Custom port
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Programmatic
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { RegistryServer, CertificateStore } from '@sentinel-atl/registry';
|
|
26
|
+
|
|
27
|
+
const server = new RegistryServer({ port: 3200 });
|
|
28
|
+
await server.start();
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### With Persistent Storage
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { RegistryServer, CertificateStore } from '@sentinel-atl/registry';
|
|
35
|
+
import { RedisStore } from '@sentinel-atl/store';
|
|
36
|
+
|
|
37
|
+
const backend = new RedisStore({ url: 'redis://localhost:6379' });
|
|
38
|
+
const store = new CertificateStore({ backend });
|
|
39
|
+
const server = new RegistryServer({ port: 3200, store });
|
|
40
|
+
await server.start(); // Loads existing certificates from backend
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## API Endpoints
|
|
44
|
+
|
|
45
|
+
### Certificates
|
|
46
|
+
|
|
47
|
+
| Method | Path | Description |
|
|
48
|
+
|--------|------|-------------|
|
|
49
|
+
| `POST` | `/api/v1/certificates` | Register a new STC |
|
|
50
|
+
| `GET` | `/api/v1/certificates/:id` | Get certificate by ID |
|
|
51
|
+
| `GET` | `/api/v1/certificates` | Query certificates (filters: `package`, `grade`, `minScore`, `limit`, `offset`) |
|
|
52
|
+
| `DELETE` | `/api/v1/certificates/:id` | Remove a certificate |
|
|
53
|
+
|
|
54
|
+
### Packages
|
|
55
|
+
|
|
56
|
+
| Method | Path | Description |
|
|
57
|
+
|--------|------|-------------|
|
|
58
|
+
| `GET` | `/api/v1/packages/:name` | Latest certificate for package |
|
|
59
|
+
| `GET` | `/api/v1/packages/:name/history` | All certificates for package |
|
|
60
|
+
| `GET` | `/api/v1/packages/:name/badge` | SVG grade badge |
|
|
61
|
+
| `GET` | `/api/v1/packages/:name/badge/score` | SVG score badge |
|
|
62
|
+
|
|
63
|
+
### Utility
|
|
64
|
+
|
|
65
|
+
| Method | Path | Description |
|
|
66
|
+
|--------|------|-------------|
|
|
67
|
+
| `GET` | `/api/v1/stats` | Registry statistics |
|
|
68
|
+
| `GET` | `/health` | Health check |
|
|
69
|
+
|
|
70
|
+
## Configuration
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
const server = new RegistryServer({
|
|
74
|
+
port: 3200,
|
|
75
|
+
store: new CertificateStore({ backend }),
|
|
76
|
+
auth: { enabled: true, keys: [{ key: 'secret', scopes: ['admin'] }] },
|
|
77
|
+
cors: { allowedOrigins: ['https://example.com'] },
|
|
78
|
+
tls: { certPath: './cert.pem', keyPath: './key.pem' },
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Environment Variables
|
|
83
|
+
|
|
84
|
+
| Variable | Description |
|
|
85
|
+
|----------|-------------|
|
|
86
|
+
| `SENTINEL_API_KEYS` | API key auth — format: `key1:read,write;key2:admin` |
|
|
87
|
+
| `SENTINEL_CORS_ORIGINS` | Comma-separated allowed origins (default: `*`) |
|
|
88
|
+
| `SENTINEL_TLS_CERT_PATH` | Path to TLS certificate |
|
|
89
|
+
| `SENTINEL_TLS_KEY_PATH` | Path to TLS private key |
|
|
90
|
+
|
|
91
|
+
## Security
|
|
92
|
+
|
|
93
|
+
The registry enforces:
|
|
94
|
+
- **Content-Type validation** — POST endpoints require `application/json`
|
|
95
|
+
- **STC schema validation** — Validates all required fields, score ranges, grade values
|
|
96
|
+
- **Security headers** — CSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy
|
|
97
|
+
- **HSTS** — Enabled automatically when TLS is active
|
|
98
|
+
- **API key auth** — Optional, with scoped access control
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
MIT
|
package/dist/badge.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Badge SVG generator — produces shields.io-style trust badges.
|
|
3
|
+
*
|
|
4
|
+
* Badge formats:
|
|
5
|
+
* - Trust grade badge: "Sentinel | A" (green)
|
|
6
|
+
* - Trust score badge: "Trust Score | 87/100" (green)
|
|
7
|
+
* - Verified badge: "Sentinel Verified | ✓" (green)
|
|
8
|
+
* - Not found badge: "Sentinel | Not Found" (gray)
|
|
9
|
+
*/
|
|
10
|
+
export type BadgeStyle = 'flat' | 'flat-square';
|
|
11
|
+
export interface BadgeOptions {
|
|
12
|
+
/** Left label text */
|
|
13
|
+
label?: string;
|
|
14
|
+
/** Right value text */
|
|
15
|
+
value: string;
|
|
16
|
+
/** Color of the right side */
|
|
17
|
+
color: string;
|
|
18
|
+
/** Badge style */
|
|
19
|
+
style?: BadgeStyle;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Generate a trust grade badge SVG.
|
|
23
|
+
*/
|
|
24
|
+
export declare function gradeBadge(grade: string, style?: BadgeStyle): string;
|
|
25
|
+
/**
|
|
26
|
+
* Generate a trust score badge SVG.
|
|
27
|
+
*/
|
|
28
|
+
export declare function scoreBadge(score: number, style?: BadgeStyle): string;
|
|
29
|
+
/**
|
|
30
|
+
* Generate a "Sentinel Verified" badge SVG.
|
|
31
|
+
*/
|
|
32
|
+
export declare function verifiedBadge(verified: boolean, style?: BadgeStyle): string;
|
|
33
|
+
/**
|
|
34
|
+
* Generate a "not found" badge SVG.
|
|
35
|
+
*/
|
|
36
|
+
export declare function notFoundBadge(style?: BadgeStyle): string;
|
|
37
|
+
//# sourceMappingURL=badge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../src/badge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,aAAa,CAAC;AAEhD,MAAM,WAAW,YAAY;IAC3B,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;AAqED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,MAAM,CAOpE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,MAAM,CAOpE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,MAAM,CAO3E;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,MAAM,CAOxD"}
|
package/dist/badge.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Badge SVG generator — produces shields.io-style trust badges.
|
|
3
|
+
*
|
|
4
|
+
* Badge formats:
|
|
5
|
+
* - Trust grade badge: "Sentinel | A" (green)
|
|
6
|
+
* - Trust score badge: "Trust Score | 87/100" (green)
|
|
7
|
+
* - Verified badge: "Sentinel Verified | ✓" (green)
|
|
8
|
+
* - Not found badge: "Sentinel | Not Found" (gray)
|
|
9
|
+
*/
|
|
10
|
+
// ─── Color Mapping ───────────────────────────────────────────────────
|
|
11
|
+
const GRADE_COLORS = {
|
|
12
|
+
A: '#4c1', // bright green
|
|
13
|
+
B: '#97ca00', // yellow-green
|
|
14
|
+
C: '#dfb317', // yellow
|
|
15
|
+
D: '#fe7d37', // orange
|
|
16
|
+
F: '#e05d44', // red
|
|
17
|
+
};
|
|
18
|
+
function scoreColor(score) {
|
|
19
|
+
if (score >= 90)
|
|
20
|
+
return GRADE_COLORS.A;
|
|
21
|
+
if (score >= 75)
|
|
22
|
+
return GRADE_COLORS.B;
|
|
23
|
+
if (score >= 60)
|
|
24
|
+
return GRADE_COLORS.C;
|
|
25
|
+
if (score >= 40)
|
|
26
|
+
return GRADE_COLORS.D;
|
|
27
|
+
return GRADE_COLORS.F;
|
|
28
|
+
}
|
|
29
|
+
// ─── SVG Generator ───────────────────────────────────────────────────
|
|
30
|
+
function escapeXml(str) {
|
|
31
|
+
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
32
|
+
}
|
|
33
|
+
function textWidth(text) {
|
|
34
|
+
// Approximate character widths for Verdana 11px
|
|
35
|
+
return text.length * 6.5 + 10;
|
|
36
|
+
}
|
|
37
|
+
function renderBadge(options) {
|
|
38
|
+
const label = options.label ?? 'Sentinel';
|
|
39
|
+
const { value, color } = options;
|
|
40
|
+
const isSquare = options.style === 'flat-square';
|
|
41
|
+
const labelWidth = textWidth(label);
|
|
42
|
+
const valueWidth = textWidth(value);
|
|
43
|
+
const totalWidth = labelWidth + valueWidth;
|
|
44
|
+
const radius = isSquare ? 0 : 3;
|
|
45
|
+
const escapedLabel = escapeXml(label);
|
|
46
|
+
const escapedValue = escapeXml(value);
|
|
47
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${totalWidth}" height="20" role="img" aria-label="${escapedLabel}: ${escapedValue}">
|
|
48
|
+
<title>${escapedLabel}: ${escapedValue}</title>
|
|
49
|
+
<linearGradient id="s" x2="0" y2="100%">
|
|
50
|
+
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
|
51
|
+
<stop offset="1" stop-opacity=".1"/>
|
|
52
|
+
</linearGradient>
|
|
53
|
+
<clipPath id="r">
|
|
54
|
+
<rect width="${totalWidth}" height="20" rx="${radius}" fill="#fff"/>
|
|
55
|
+
</clipPath>
|
|
56
|
+
<g clip-path="url(#r)">
|
|
57
|
+
<rect width="${labelWidth}" height="20" fill="#555"/>
|
|
58
|
+
<rect x="${labelWidth}" width="${valueWidth}" height="20" fill="${color}"/>
|
|
59
|
+
<rect width="${totalWidth}" height="20" fill="url(#s)"/>
|
|
60
|
+
</g>
|
|
61
|
+
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
|
62
|
+
<text aria-hidden="true" x="${labelWidth / 2}" y="15" fill="#010101" fill-opacity=".3">${escapedLabel}</text>
|
|
63
|
+
<text x="${labelWidth / 2}" y="14">${escapedLabel}</text>
|
|
64
|
+
<text aria-hidden="true" x="${labelWidth + valueWidth / 2}" y="15" fill="#010101" fill-opacity=".3">${escapedValue}</text>
|
|
65
|
+
<text x="${labelWidth + valueWidth / 2}" y="14">${escapedValue}</text>
|
|
66
|
+
</g>
|
|
67
|
+
</svg>`;
|
|
68
|
+
}
|
|
69
|
+
// ─── Public API ──────────────────────────────────────────────────────
|
|
70
|
+
/**
|
|
71
|
+
* Generate a trust grade badge SVG.
|
|
72
|
+
*/
|
|
73
|
+
export function gradeBadge(grade, style) {
|
|
74
|
+
return renderBadge({
|
|
75
|
+
label: 'Sentinel',
|
|
76
|
+
value: `Grade ${grade}`,
|
|
77
|
+
color: GRADE_COLORS[grade] ?? '#9f9f9f',
|
|
78
|
+
style,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Generate a trust score badge SVG.
|
|
83
|
+
*/
|
|
84
|
+
export function scoreBadge(score, style) {
|
|
85
|
+
return renderBadge({
|
|
86
|
+
label: 'Trust Score',
|
|
87
|
+
value: `${score}/100`,
|
|
88
|
+
color: scoreColor(score),
|
|
89
|
+
style,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Generate a "Sentinel Verified" badge SVG.
|
|
94
|
+
*/
|
|
95
|
+
export function verifiedBadge(verified, style) {
|
|
96
|
+
return renderBadge({
|
|
97
|
+
label: 'Sentinel',
|
|
98
|
+
value: verified ? 'Verified ✓' : 'Unverified',
|
|
99
|
+
color: verified ? '#4c1' : '#9f9f9f',
|
|
100
|
+
style,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Generate a "not found" badge SVG.
|
|
105
|
+
*/
|
|
106
|
+
export function notFoundBadge(style) {
|
|
107
|
+
return renderBadge({
|
|
108
|
+
label: 'Sentinel',
|
|
109
|
+
value: 'Not Found',
|
|
110
|
+
color: '#9f9f9f',
|
|
111
|
+
style,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=badge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badge.js","sourceRoot":"","sources":["../src/badge.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
process.on('unhandledRejection', (err) => {
|
|
3
|
+
console.error('Unhandled rejection:', err);
|
|
4
|
+
process.exit(1);
|
|
5
|
+
});
|
|
6
|
+
process.on('uncaughtException', (err) => {
|
|
7
|
+
console.error('Uncaught exception:', err);
|
|
8
|
+
process.exit(1);
|
|
9
|
+
});
|
|
10
|
+
/**
|
|
11
|
+
* sentinel-registry — CLI for running the Trust Registry API server.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* sentinel-registry Start on default port 3200
|
|
15
|
+
* sentinel-registry --port 8080 Start on custom port
|
|
16
|
+
*/
|
|
17
|
+
import { RegistryServer } from './server.js';
|
|
18
|
+
import { authConfigFromEnv, corsConfigFromEnv, tlsConfigFromEnv } from '@sentinel-atl/hardening';
|
|
19
|
+
const args = process.argv.slice(2);
|
|
20
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
21
|
+
console.log('🗂️ Sentinel Trust Registry');
|
|
22
|
+
console.log();
|
|
23
|
+
console.log('Usage:');
|
|
24
|
+
console.log(' sentinel-registry Start on port 3200');
|
|
25
|
+
console.log(' sentinel-registry --port <port> Start on custom port');
|
|
26
|
+
console.log();
|
|
27
|
+
console.log('Endpoints:');
|
|
28
|
+
console.log(' POST /api/v1/certificates Register an STC');
|
|
29
|
+
console.log(' GET /api/v1/certificates/:id Get by ID');
|
|
30
|
+
console.log(' GET /api/v1/certificates Query certificates');
|
|
31
|
+
console.log(' DELETE /api/v1/certificates/:id Remove');
|
|
32
|
+
console.log(' GET /api/v1/packages/:name Latest cert for package');
|
|
33
|
+
console.log(' GET /api/v1/packages/:name/badge SVG trust badge');
|
|
34
|
+
console.log(' GET /api/v1/stats Registry stats');
|
|
35
|
+
console.log(' GET /health Health check');
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
const portIdx = args.indexOf('--port');
|
|
39
|
+
const port = portIdx !== -1 ? parseInt(args[portIdx + 1]) : 3200;
|
|
40
|
+
const server = new RegistryServer({
|
|
41
|
+
port,
|
|
42
|
+
auth: authConfigFromEnv(),
|
|
43
|
+
cors: corsConfigFromEnv(),
|
|
44
|
+
tls: tlsConfigFromEnv(),
|
|
45
|
+
});
|
|
46
|
+
console.log('🗂️ Sentinel Trust Registry');
|
|
47
|
+
const { port: actualPort } = await server.start();
|
|
48
|
+
const proto = server.isTLS() ? 'https' : 'http';
|
|
49
|
+
console.log(` Listening on ${proto}://localhost:${actualPort}`);
|
|
50
|
+
console.log();
|
|
51
|
+
console.log(' Endpoints:');
|
|
52
|
+
console.log(' POST /api/v1/certificates');
|
|
53
|
+
console.log(' GET /api/v1/certificates/:id');
|
|
54
|
+
console.log(' GET /api/v1/packages/:name');
|
|
55
|
+
console.log(' GET /api/v1/packages/:name/badge');
|
|
56
|
+
console.log(' GET /api/v1/stats');
|
|
57
|
+
console.log(' GET /health');
|
|
58
|
+
console.log();
|
|
59
|
+
const shutdown = async () => {
|
|
60
|
+
console.log('\n Shutting down...');
|
|
61
|
+
await server.stop();
|
|
62
|
+
process.exit(0);
|
|
63
|
+
};
|
|
64
|
+
process.on('SIGINT', shutdown);
|
|
65
|
+
process.on('SIGTERM', shutdown);
|
|
66
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sentinel-atl/registry — Trust Registry API
|
|
3
|
+
*
|
|
4
|
+
* Publish, query, and verify Sentinel Trust Certificates.
|
|
5
|
+
* Serves SVG trust badges for READMEs and dashboards.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* sentinel-registry --port 3200
|
|
9
|
+
*/
|
|
10
|
+
export { CertificateStore, type CertificateStoreOptions, type RegistryEntry, type RegistryQuery, type RegistryStats, } from './store.js';
|
|
11
|
+
export { RegistryServer, type RegistryServerOptions, } from './server.js';
|
|
12
|
+
export { gradeBadge, scoreBadge, verifiedBadge, notFoundBadge, type BadgeStyle, type BadgeOptions, } from './badge.js';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,aAAa,GACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,cAAc,EACd,KAAK,qBAAqB,GAC3B,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,UAAU,EACV,UAAU,EACV,aAAa,EACb,aAAa,EACb,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sentinel-atl/registry — Trust Registry API
|
|
3
|
+
*
|
|
4
|
+
* Publish, query, and verify Sentinel Trust Certificates.
|
|
5
|
+
* Serves SVG trust badges for READMEs and dashboards.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* sentinel-registry --port 3200
|
|
9
|
+
*/
|
|
10
|
+
export { CertificateStore, } from './store.js';
|
|
11
|
+
export { RegistryServer, } from './server.js';
|
|
12
|
+
export { gradeBadge, scoreBadge, verifiedBadge, notFoundBadge, } from './badge.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,gBAAgB,GAKjB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,cAAc,GAEf,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,UAAU,EACV,UAAU,EACV,aAAa,EACb,aAAa,GAGd,MAAM,YAAY,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trust Registry HTTP API — REST endpoints for publishing and querying STCs.
|
|
3
|
+
*
|
|
4
|
+
* Endpoints:
|
|
5
|
+
* POST /api/v1/certificates Register a new STC
|
|
6
|
+
* GET /api/v1/certificates/:id Get certificate by ID
|
|
7
|
+
* GET /api/v1/certificates Query certificates
|
|
8
|
+
* DELETE /api/v1/certificates/:id Remove a certificate
|
|
9
|
+
*
|
|
10
|
+
* GET /api/v1/packages/:name Get latest certificate for a package
|
|
11
|
+
* GET /api/v1/packages/:name/history Get all certificates for a package
|
|
12
|
+
* GET /api/v1/packages/:name/badge SVG badge for a package
|
|
13
|
+
* GET /api/v1/packages/:name/badge/score Score badge
|
|
14
|
+
*
|
|
15
|
+
* GET /api/v1/stats Registry stats
|
|
16
|
+
* GET /health Health check
|
|
17
|
+
*/
|
|
18
|
+
import { CertificateStore } from './store.js';
|
|
19
|
+
import { type AuthConfig, type CorsConfig, type TlsConfig } from '@sentinel-atl/hardening';
|
|
20
|
+
export interface RegistryServerOptions {
|
|
21
|
+
/** Port to listen on */
|
|
22
|
+
port?: number;
|
|
23
|
+
/** Pre-configured certificate store */
|
|
24
|
+
store?: CertificateStore;
|
|
25
|
+
/** API key authentication config */
|
|
26
|
+
auth?: AuthConfig;
|
|
27
|
+
/** CORS configuration */
|
|
28
|
+
cors?: CorsConfig;
|
|
29
|
+
/** TLS configuration */
|
|
30
|
+
tls?: TlsConfig;
|
|
31
|
+
}
|
|
32
|
+
export declare class RegistryServer {
|
|
33
|
+
private server;
|
|
34
|
+
private store;
|
|
35
|
+
private port;
|
|
36
|
+
private authConfig;
|
|
37
|
+
private corsConfig;
|
|
38
|
+
private tlsConfig?;
|
|
39
|
+
constructor(options?: RegistryServerOptions);
|
|
40
|
+
getStore(): CertificateStore;
|
|
41
|
+
start(): Promise<{
|
|
42
|
+
port: number;
|
|
43
|
+
}>;
|
|
44
|
+
stop(): Promise<void>;
|
|
45
|
+
isTLS(): boolean;
|
|
46
|
+
private handleRequest;
|
|
47
|
+
private handleRegister;
|
|
48
|
+
private handleGetById;
|
|
49
|
+
private handleDelete;
|
|
50
|
+
private handleQuery;
|
|
51
|
+
private handleGetPackage;
|
|
52
|
+
private handlePackageHistory;
|
|
53
|
+
private handleBadge;
|
|
54
|
+
private handleScoreBadge;
|
|
55
|
+
private formatEntry;
|
|
56
|
+
private sendJson;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,gBAAgB,EAAsB,MAAM,YAAY,CAAC;AAElE,OAAO,EAKL,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EACjD,MAAM,yBAAyB,CAAC;AAKjC,MAAM,WAAW,qBAAqB;IACpC,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,oCAAoC;IACpC,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,yBAAyB;IACzB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,wBAAwB;IACxB,GAAG,CAAC,EAAE,SAAS,CAAC;CACjB;AAID,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,SAAS,CAAC,CAAY;gBAElB,OAAO,CAAC,EAAE,qBAAqB;IAa3C,QAAQ,IAAI,gBAAgB;IAItB,KAAK,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAgBlC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAU3B,KAAK,IAAI,OAAO;YAMF,aAAa;YAyEb,cAAc;IAuC5B,OAAO,CAAC,aAAa;YAQP,YAAY;IAQ1B,OAAO,CAAC,WAAW;IAwBnB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,WAAW;IAoBnB,OAAO,CAAC,gBAAgB;IAoBxB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,QAAQ;CAIjB"}
|