@generacy-ai/control-plane 0.4.0 → 0.6.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 +5 -0
- package/dist/bin/control-plane.js +38 -0
- package/dist/bin/control-plane.js.map +1 -1
- package/dist/bin/git-credential-generacy.d.ts +3 -0
- package/dist/bin/git-credential-generacy.d.ts.map +1 -0
- package/dist/bin/git-credential-generacy.js +158 -0
- package/dist/bin/git-credential-generacy.js.map +1 -0
- package/dist/bin/git-token-proxy.d.ts +3 -0
- package/dist/bin/git-token-proxy.d.ts.map +1 -0
- package/dist/bin/git-token-proxy.js +70 -0
- package/dist/bin/git-token-proxy.js.map +1 -0
- package/dist/src/git-token-proxy/allowlists.d.ts +17 -0
- package/dist/src/git-token-proxy/allowlists.d.ts.map +1 -0
- package/dist/src/git-token-proxy/allowlists.js +38 -0
- package/dist/src/git-token-proxy/allowlists.js.map +1 -0
- package/dist/src/git-token-proxy/handler.d.ts +10 -0
- package/dist/src/git-token-proxy/handler.d.ts.map +1 -0
- package/dist/src/git-token-proxy/handler.js +86 -0
- package/dist/src/git-token-proxy/handler.js.map +1 -0
- package/dist/src/git-token-proxy/index.d.ts +5 -0
- package/dist/src/git-token-proxy/index.d.ts.map +1 -0
- package/dist/src/git-token-proxy/index.js +5 -0
- package/dist/src/git-token-proxy/index.js.map +1 -0
- package/dist/src/git-token-proxy/logging.d.ts +9 -0
- package/dist/src/git-token-proxy/logging.d.ts.map +1 -0
- package/dist/src/git-token-proxy/logging.js +14 -0
- package/dist/src/git-token-proxy/logging.js.map +1 -0
- package/dist/src/git-token-proxy/upstream-errors.d.ts +14 -0
- package/dist/src/git-token-proxy/upstream-errors.d.ts.map +1 -0
- package/dist/src/git-token-proxy/upstream-errors.js +10 -0
- package/dist/src/git-token-proxy/upstream-errors.js.map +1 -0
- package/dist/src/router.d.ts.map +1 -1
- package/dist/src/router.js +7 -0
- package/dist/src/router.js.map +1 -1
- package/dist/src/routes/git-token.d.ts +15 -0
- package/dist/src/routes/git-token.d.ts.map +1 -0
- package/dist/src/routes/git-token.js +85 -0
- package/dist/src/routes/git-token.js.map +1 -0
- package/dist/src/schemas.d.ts +30 -0
- package/dist/src/schemas.d.ts.map +1 -1
- package/dist/src/schemas.js +12 -0
- package/dist/src/schemas.js.map +1 -1
- package/dist/src/services/cloud-pull-client.d.ts +19 -0
- package/dist/src/services/cloud-pull-client.d.ts.map +1 -0
- package/dist/src/services/cloud-pull-client.js +149 -0
- package/dist/src/services/cloud-pull-client.js.map +1 -0
- package/dist/src/services/cluster-api-key.d.ts +8 -0
- package/dist/src/services/cluster-api-key.d.ts.map +1 -0
- package/dist/src/services/cluster-api-key.js +39 -0
- package/dist/src/services/cluster-api-key.js.map +1 -0
- package/dist/src/services/git-token-manager.d.ts +17 -0
- package/dist/src/services/git-token-manager.d.ts.map +1 -0
- package/dist/src/services/git-token-manager.js +73 -0
- package/dist/src/services/git-token-manager.js.map +1 -0
- package/dist/src/services/wizard-env-writer.d.ts.map +1 -1
- package/dist/src/services/wizard-env-writer.js +13 -3
- package/dist/src/services/wizard-env-writer.js.map +1 -1
- package/dist/src/types/git-token.d.ts +24 -0
- package/dist/src/types/git-token.d.ts.map +1 -0
- package/dist/src/types/git-token.js +13 -0
- package/dist/src/types/git-token.js.map +1 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -20,9 +20,14 @@ Socket is created with mode `0660` (owner + group read/write).
|
|
|
20
20
|
| GET | `/roles/:id` | Returns stub role config |
|
|
21
21
|
| PUT | `/roles/:id` | Accepts role update, returns `{ ok: true }` |
|
|
22
22
|
| POST | `/lifecycle/:action` | Triggers lifecycle action (`clone-peer-repos`, `code-server-start`, `code-server-stop`) |
|
|
23
|
+
| POST | `/git-token` | Returns a fresh GitHub installation token + `expiresAt` for git ops (#766) |
|
|
23
24
|
|
|
24
25
|
All routes are stubs in this phase. Real wiring to credhelper daemon and orchestrator lands in later phases.
|
|
25
26
|
|
|
27
|
+
## `git-credential-generacy` bin
|
|
28
|
+
|
|
29
|
+
Companion CLI bin shipped from this package. Speaks the git credential-helper line protocol — on `get` it connects to the control socket, POSTs `/git-token`, and prints `username=x-access-token\npassword=<token>\n` to stdout. `store` and `erase` are no-ops. Failures surface as `generacy-git-helper: <CODE>: <message>` on stderr with distinct exit codes per failure mode (2–9). See [`specs/766-summary-implement-git/quickstart.md`](../../specs/766-summary-implement-git/quickstart.md) for the protocol details and integration steps.
|
|
30
|
+
|
|
26
31
|
## Actor Headers
|
|
27
32
|
|
|
28
33
|
The relay dispatcher injects identity headers on every forwarded request:
|
|
@@ -10,6 +10,11 @@ import { AppConfigEnvStore } from '../src/services/app-config-env-store.js';
|
|
|
10
10
|
import { AppConfigFileStore } from '../src/services/app-config-file-store.js';
|
|
11
11
|
import { AppConfigSecretEnvStore } from '../src/services/app-config-secret-env-store.js';
|
|
12
12
|
import { setAppConfigStores, readManifest } from '../src/routes/app-config.js';
|
|
13
|
+
import YAML from 'yaml';
|
|
14
|
+
import { createClusterApiKeyReader } from '../src/services/cluster-api-key.js';
|
|
15
|
+
import { createCloudPullClient } from '../src/services/cloud-pull-client.js';
|
|
16
|
+
import { createGitTokenManager } from '../src/services/git-token-manager.js';
|
|
17
|
+
import { setGitTokenManager } from '../src/routes/git-token.js';
|
|
13
18
|
const DEFAULT_SOCKET_PATH = '/run/generacy-control-plane/control.sock';
|
|
14
19
|
const socketPath = process.env['CONTROL_PLANE_SOCKET_PATH'] ?? DEFAULT_SOCKET_PATH;
|
|
15
20
|
const deploymentMode = (process.env['DEPLOYMENT_MODE'] ?? 'local');
|
|
@@ -77,11 +82,44 @@ async function writeInitResult(initResult) {
|
|
|
77
82
|
console.error('[control-plane] Failed to write init-result.json:', err instanceof Error ? err.message : String(err));
|
|
78
83
|
}
|
|
79
84
|
}
|
|
85
|
+
async function resolveDefaultGithubAppCredentialId(agencyDir) {
|
|
86
|
+
const yamlPath = path.join(agencyDir, 'credentials.yaml');
|
|
87
|
+
try {
|
|
88
|
+
const raw = await fs.readFile(yamlPath, 'utf8');
|
|
89
|
+
const parsed = YAML.parse(raw);
|
|
90
|
+
if (parsed?.credentials && typeof parsed.credentials === 'object') {
|
|
91
|
+
for (const [id, entry] of Object.entries(parsed.credentials)) {
|
|
92
|
+
if (entry && typeof entry === 'object' && entry.type === 'github-app') {
|
|
93
|
+
return id;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// Fall through to literal default below.
|
|
100
|
+
}
|
|
101
|
+
return 'github-app';
|
|
102
|
+
}
|
|
80
103
|
credentialBackend
|
|
81
104
|
.init()
|
|
82
105
|
.then(async () => {
|
|
83
106
|
setCredentialBackend(credentialBackend);
|
|
84
107
|
console.log('[control-plane] Credential backend initialized');
|
|
108
|
+
// Wire JIT git credential helper services (#766). Cluster API key reader
|
|
109
|
+
// reads /var/lib/generacy/cluster-api-key (mtime-cached); cloud pull client
|
|
110
|
+
// talks to generacy-cloud#817; git-token manager fronts both with an
|
|
111
|
+
// in-memory token cache + concurrent-call dedup.
|
|
112
|
+
const agencyDir = process.env['CREDHELPER_AGENCY_DIR'] ?? '.agency';
|
|
113
|
+
const defaultGithubAppCredentialId = await resolveDefaultGithubAppCredentialId(agencyDir);
|
|
114
|
+
const clusterApiKeyReader = createClusterApiKeyReader();
|
|
115
|
+
const cloudPullClient = createCloudPullClient({ apiKeyReader: clusterApiKeyReader });
|
|
116
|
+
const gitTokenManager = createGitTokenManager({ cloudPullClient });
|
|
117
|
+
setGitTokenManager(gitTokenManager, defaultGithubAppCredentialId);
|
|
118
|
+
console.log(JSON.stringify({
|
|
119
|
+
event: 'git-token-init',
|
|
120
|
+
defaultCredentialId: defaultGithubAppCredentialId,
|
|
121
|
+
apiUrlConfigured: Boolean(process.env['GENERACY_API_URL']),
|
|
122
|
+
}));
|
|
85
123
|
// Initialize app-config stores individually with structured error handling
|
|
86
124
|
const initResult = { stores: {}, warnings: [] };
|
|
87
125
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-plane.js","sourceRoot":"","sources":["../../bin/control-plane.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAC5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,gDAAgD,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"control-plane.js","sourceRoot":"","sources":["../../bin/control-plane.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-credential-generacy.d.ts","sourceRoot":"","sources":["../../bin/git-credential-generacy.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import http from 'node:http';
|
|
3
|
+
const DEFAULT_SOCKET_PATH = '/run/generacy-control-plane/control.sock';
|
|
4
|
+
const EXIT_CODE_BY_CODE = {
|
|
5
|
+
CONTROL_SOCKET_UNREACHABLE: 2,
|
|
6
|
+
CLUSTER_API_KEY_MISSING: 3,
|
|
7
|
+
CLOUD_UNREACHABLE: 4,
|
|
8
|
+
CLOUD_AUTH_REJECTED: 5,
|
|
9
|
+
CLOUD_REQUEST_INVALID: 6,
|
|
10
|
+
CLOUD_UPSTREAM_ERROR: 7,
|
|
11
|
+
CLOUD_RESPONSE_INVALID: 8,
|
|
12
|
+
CREDENTIAL_NOT_CONFIGURED: 9,
|
|
13
|
+
INTERNAL_ERROR: 1,
|
|
14
|
+
};
|
|
15
|
+
function exitErr(outcome) {
|
|
16
|
+
process.stderr.write(`generacy-git-helper: ${outcome.code}: ${outcome.message}\n`);
|
|
17
|
+
process.exit(outcome.exitCode);
|
|
18
|
+
}
|
|
19
|
+
function readStdin() {
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
const chunks = [];
|
|
22
|
+
process.stdin.on('data', (c) => chunks.push(c));
|
|
23
|
+
process.stdin.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
|
|
24
|
+
process.stdin.on('error', reject);
|
|
25
|
+
// If stdin is closed before any data, 'end' fires naturally.
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function parseInput(raw) {
|
|
29
|
+
const attrs = {};
|
|
30
|
+
for (const line of raw.split('\n')) {
|
|
31
|
+
if (line === '')
|
|
32
|
+
break;
|
|
33
|
+
const eq = line.indexOf('=');
|
|
34
|
+
if (eq === -1)
|
|
35
|
+
continue;
|
|
36
|
+
const key = line.slice(0, eq);
|
|
37
|
+
const value = line.slice(eq + 1);
|
|
38
|
+
if (key === 'protocol')
|
|
39
|
+
attrs.protocol = value;
|
|
40
|
+
else if (key === 'host')
|
|
41
|
+
attrs.host = value;
|
|
42
|
+
}
|
|
43
|
+
return attrs;
|
|
44
|
+
}
|
|
45
|
+
function postToControlSocket(socketPath) {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
const req = http.request({
|
|
48
|
+
socketPath,
|
|
49
|
+
path: '/git-token',
|
|
50
|
+
method: 'POST',
|
|
51
|
+
headers: {
|
|
52
|
+
'content-type': 'application/json',
|
|
53
|
+
'content-length': '2',
|
|
54
|
+
},
|
|
55
|
+
}, (res) => {
|
|
56
|
+
const chunks = [];
|
|
57
|
+
res.on('data', (c) => chunks.push(c));
|
|
58
|
+
res.on('end', () => {
|
|
59
|
+
resolve({ status: res.statusCode ?? 0, body: Buffer.concat(chunks).toString('utf8') });
|
|
60
|
+
});
|
|
61
|
+
res.on('error', reject);
|
|
62
|
+
});
|
|
63
|
+
req.on('error', reject);
|
|
64
|
+
req.write('{}');
|
|
65
|
+
req.end();
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
async function runGet(socketPath, input) {
|
|
69
|
+
if (input.host !== 'github.com') {
|
|
70
|
+
// Defensive bypass — git's per-host config should already prevent this.
|
|
71
|
+
process.exit(0);
|
|
72
|
+
}
|
|
73
|
+
let response;
|
|
74
|
+
try {
|
|
75
|
+
response = await postToControlSocket(socketPath);
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
const cause = err.code ?? err.message;
|
|
79
|
+
exitErr({
|
|
80
|
+
code: 'CONTROL_SOCKET_UNREACHABLE',
|
|
81
|
+
message: `control socket at ${socketPath} unreachable (${cause})`,
|
|
82
|
+
exitCode: EXIT_CODE_BY_CODE.CONTROL_SOCKET_UNREACHABLE,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (response.status >= 200 && response.status < 300) {
|
|
86
|
+
let parsed;
|
|
87
|
+
try {
|
|
88
|
+
parsed = JSON.parse(response.body);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
exitErr({
|
|
92
|
+
code: 'CLOUD_RESPONSE_INVALID',
|
|
93
|
+
message: 'control-plane returned a non-JSON body on success',
|
|
94
|
+
exitCode: EXIT_CODE_BY_CODE.CLOUD_RESPONSE_INVALID,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (typeof parsed.token !== 'string' || parsed.token.length === 0) {
|
|
98
|
+
exitErr({
|
|
99
|
+
code: 'CLOUD_RESPONSE_INVALID',
|
|
100
|
+
message: 'control-plane response missing token',
|
|
101
|
+
exitCode: EXIT_CODE_BY_CODE.CLOUD_RESPONSE_INVALID,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
const out = [];
|
|
105
|
+
if (input.protocol)
|
|
106
|
+
out.push(`protocol=${input.protocol}`);
|
|
107
|
+
if (input.host)
|
|
108
|
+
out.push(`host=${input.host}`);
|
|
109
|
+
out.push('username=x-access-token');
|
|
110
|
+
out.push(`password=${parsed.token}`);
|
|
111
|
+
out.push(''); // trailing blank line
|
|
112
|
+
process.stdout.write(out.join('\n'));
|
|
113
|
+
process.exit(0);
|
|
114
|
+
}
|
|
115
|
+
// Non-2xx — extract code/message from error body if possible.
|
|
116
|
+
let code = 'INTERNAL_ERROR';
|
|
117
|
+
let message = `control-plane returned HTTP ${response.status}`;
|
|
118
|
+
try {
|
|
119
|
+
const errBody = JSON.parse(response.body);
|
|
120
|
+
if (typeof errBody.code === 'string' && errBody.code in EXIT_CODE_BY_CODE) {
|
|
121
|
+
code = errBody.code;
|
|
122
|
+
}
|
|
123
|
+
if (typeof errBody.error === 'string') {
|
|
124
|
+
message = errBody.error;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Fall through to defaults.
|
|
129
|
+
}
|
|
130
|
+
const exitCode = EXIT_CODE_BY_CODE[code] ?? EXIT_CODE_BY_CODE.INTERNAL_ERROR;
|
|
131
|
+
exitErr({ code, message, exitCode });
|
|
132
|
+
}
|
|
133
|
+
async function main() {
|
|
134
|
+
const action = process.argv[2];
|
|
135
|
+
if (action !== 'get' && action !== 'store' && action !== 'erase') {
|
|
136
|
+
exitErr({
|
|
137
|
+
code: 'INTERNAL_ERROR',
|
|
138
|
+
message: `unknown action ${action ?? '<none>'}`,
|
|
139
|
+
exitCode: EXIT_CODE_BY_CODE.INTERNAL_ERROR,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
const raw = await readStdin();
|
|
143
|
+
if (action === 'store' || action === 'erase') {
|
|
144
|
+
process.exit(0);
|
|
145
|
+
}
|
|
146
|
+
const input = parseInput(raw);
|
|
147
|
+
const socketPath = process.env['CONTROL_PLANE_SOCKET_PATH'] ?? DEFAULT_SOCKET_PATH;
|
|
148
|
+
await runGet(socketPath, input);
|
|
149
|
+
}
|
|
150
|
+
main().catch((err) => {
|
|
151
|
+
// Defensive catch — main() should never throw past runGet/exitErr.
|
|
152
|
+
exitErr({
|
|
153
|
+
code: 'INTERNAL_ERROR',
|
|
154
|
+
message: err instanceof Error ? err.message : String(err),
|
|
155
|
+
exitCode: EXIT_CODE_BY_CODE.INTERNAL_ERROR,
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
//# sourceMappingURL=git-credential-generacy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-credential-generacy.js","sourceRoot":"","sources":["../../bin/git-credential-generacy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-token-proxy.d.ts","sourceRoot":"","sources":["../../bin/git-token-proxy.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import http from 'node:http';
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import { createHandler, logProxyInit, } from '../src/git-token-proxy/index.js';
|
|
5
|
+
const DEFAULT_LISTEN_SOCKET = '/run/generacy-git-token/control.sock';
|
|
6
|
+
const DEFAULT_UPSTREAM_SOCKET = '/run/generacy-control-plane/control.sock';
|
|
7
|
+
const LISTEN_SOCKET_MODE = 0o660;
|
|
8
|
+
const SHUTDOWN_TIMEOUT_MS = 5_000;
|
|
9
|
+
function fail(message, exitCode = 1) {
|
|
10
|
+
process.stderr.write(`git-token-proxy: ${message}\n`);
|
|
11
|
+
process.exit(exitCode);
|
|
12
|
+
}
|
|
13
|
+
async function main() {
|
|
14
|
+
const listenSocketPath = process.env['GIT_TOKEN_PROXY_SOCKET'] ?? DEFAULT_LISTEN_SOCKET;
|
|
15
|
+
const upstreamSocketPath = process.env['CONTROL_PLANE_SOCKET_PATH'] ?? DEFAULT_UPSTREAM_SOCKET;
|
|
16
|
+
try {
|
|
17
|
+
await fs.unlink(listenSocketPath);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
const code = err.code;
|
|
21
|
+
if (code !== 'ENOENT') {
|
|
22
|
+
fail(`unlink failed: ${listenSocketPath}: ${code ?? 'unknown'}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const server = http.createServer(createHandler({ upstreamSocketPath }));
|
|
26
|
+
await new Promise((resolve, reject) => {
|
|
27
|
+
const onError = (err) => {
|
|
28
|
+
reject(err);
|
|
29
|
+
};
|
|
30
|
+
server.once('error', onError);
|
|
31
|
+
server.listen({ path: listenSocketPath }, () => {
|
|
32
|
+
server.removeListener('error', onError);
|
|
33
|
+
resolve();
|
|
34
|
+
});
|
|
35
|
+
}).catch((err) => {
|
|
36
|
+
const code = err.code ?? 'unknown';
|
|
37
|
+
fail(`bind failed: ${listenSocketPath}: ${code}`);
|
|
38
|
+
});
|
|
39
|
+
try {
|
|
40
|
+
await fs.chmod(listenSocketPath, LISTEN_SOCKET_MODE);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
const code = err.code ?? 'unknown';
|
|
44
|
+
fail(`chmod failed: ${listenSocketPath}: ${code}`);
|
|
45
|
+
}
|
|
46
|
+
let shuttingDown = false;
|
|
47
|
+
const shutdown = () => {
|
|
48
|
+
if (shuttingDown)
|
|
49
|
+
return;
|
|
50
|
+
shuttingDown = true;
|
|
51
|
+
const forceTimer = setTimeout(() => process.exit(1), SHUTDOWN_TIMEOUT_MS);
|
|
52
|
+
forceTimer.unref();
|
|
53
|
+
server.close(() => {
|
|
54
|
+
fs.unlink(listenSocketPath)
|
|
55
|
+
.catch(() => undefined)
|
|
56
|
+
.finally(() => process.exit(0));
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
// Register signal handlers before announcing readiness: a consumer that acts
|
|
60
|
+
// on the init line (e.g. sends SIGTERM) must not hit the default-terminate
|
|
61
|
+
// window between logging and handler registration.
|
|
62
|
+
process.on('SIGTERM', shutdown);
|
|
63
|
+
process.on('SIGINT', shutdown);
|
|
64
|
+
logProxyInit({ listenSocket: listenSocketPath, upstreamSocket: upstreamSocketPath });
|
|
65
|
+
}
|
|
66
|
+
main().catch((err) => {
|
|
67
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
68
|
+
fail(`startup failed: ${message}`);
|
|
69
|
+
});
|
|
70
|
+
//# sourceMappingURL=git-token-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-token-proxy.js","sourceRoot":"","sources":["../../bin/git-token-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type http from 'node:http';
|
|
2
|
+
/**
|
|
3
|
+
* Single-route privilege boundary. Returns true iff this method+path pair is
|
|
4
|
+
* allowed through to upstream. The only true case is POST /git-token (with
|
|
5
|
+
* optional query string). Trailing slash is significant; the query string is
|
|
6
|
+
* stripped before comparison.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isAllowedRoute(method: string | undefined, url: string | undefined): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Returns a new headers object containing ONLY 'content-type' and
|
|
11
|
+
* 'content-length' (when present in the input). All other keys are dropped.
|
|
12
|
+
* Header names are normalized to lowercase. The caller is expected to
|
|
13
|
+
* overwrite 'content-length' with the actual buffered body length before
|
|
14
|
+
* forwarding upstream.
|
|
15
|
+
*/
|
|
16
|
+
export declare function pickAllowedHeaders(headers: http.IncomingHttpHeaders): Record<string, string>;
|
|
17
|
+
//# sourceMappingURL=allowlists.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allowlists.d.ts","sourceRoot":"","sources":["../../../src/git-token-proxy/allowlists.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAM3F;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAW5F"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single-route privilege boundary. Returns true iff this method+path pair is
|
|
3
|
+
* allowed through to upstream. The only true case is POST /git-token (with
|
|
4
|
+
* optional query string). Trailing slash is significant; the query string is
|
|
5
|
+
* stripped before comparison.
|
|
6
|
+
*/
|
|
7
|
+
export function isAllowedRoute(method, url) {
|
|
8
|
+
if (method !== 'POST')
|
|
9
|
+
return false;
|
|
10
|
+
if (typeof url !== 'string')
|
|
11
|
+
return false;
|
|
12
|
+
const queryIdx = url.indexOf('?');
|
|
13
|
+
const path = queryIdx === -1 ? url : url.slice(0, queryIdx);
|
|
14
|
+
return path === '/git-token';
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Returns a new headers object containing ONLY 'content-type' and
|
|
18
|
+
* 'content-length' (when present in the input). All other keys are dropped.
|
|
19
|
+
* Header names are normalized to lowercase. The caller is expected to
|
|
20
|
+
* overwrite 'content-length' with the actual buffered body length before
|
|
21
|
+
* forwarding upstream.
|
|
22
|
+
*/
|
|
23
|
+
export function pickAllowedHeaders(headers) {
|
|
24
|
+
const out = {};
|
|
25
|
+
for (const [rawKey, rawValue] of Object.entries(headers)) {
|
|
26
|
+
const key = rawKey.toLowerCase();
|
|
27
|
+
if (key !== 'content-type' && key !== 'content-length')
|
|
28
|
+
continue;
|
|
29
|
+
if (rawValue === undefined)
|
|
30
|
+
continue;
|
|
31
|
+
const value = Array.isArray(rawValue) ? rawValue[0] : rawValue;
|
|
32
|
+
if (typeof value !== 'string')
|
|
33
|
+
continue;
|
|
34
|
+
out[key] = value;
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=allowlists.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allowlists.js","sourceRoot":"","sources":["../../../src/git-token-proxy/allowlists.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,MAA0B,EAAE,GAAuB;IAChF,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IACpC,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC1C,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC5D,OAAO,IAAI,KAAK,YAAY,CAAC;AAC/B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAiC;IAClE,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACzD,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;QACjC,IAAI,GAAG,KAAK,cAAc,IAAI,GAAG,KAAK,gBAAgB;YAAE,SAAS;QACjE,IAAI,QAAQ,KAAK,SAAS;YAAE,SAAS;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC/D,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,SAAS;QACxC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACnB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
export declare const MAX_BODY_BYTES: number;
|
|
3
|
+
export declare const UPSTREAM_TIMEOUT_MS = 30000;
|
|
4
|
+
export interface CreateHandlerOptions {
|
|
5
|
+
upstreamSocketPath: string;
|
|
6
|
+
httpRequest?: typeof http.request;
|
|
7
|
+
}
|
|
8
|
+
export type ProxyRequestHandler = (req: http.IncomingMessage, res: http.ServerResponse) => void;
|
|
9
|
+
export declare function createHandler(options: CreateHandlerOptions): ProxyRequestHandler;
|
|
10
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/git-token-proxy/handler.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAK7B,eAAO,MAAM,cAAc,QAAY,CAAC;AACxC,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAE1C,MAAM,WAAW,oBAAoB;IACnC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,IAAI,CAAC,OAAO,CAAC;CACnC;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,KAAK,IAAI,CAAC;AAEhG,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,mBAAmB,CAuFhF"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import { isAllowedRoute, pickAllowedHeaders } from './allowlists.js';
|
|
3
|
+
import { mapUpstreamErrorToCode } from './upstream-errors.js';
|
|
4
|
+
import { logUpstreamError } from './logging.js';
|
|
5
|
+
export const MAX_BODY_BYTES = 64 * 1024;
|
|
6
|
+
export const UPSTREAM_TIMEOUT_MS = 30_000;
|
|
7
|
+
export function createHandler(options) {
|
|
8
|
+
const { upstreamSocketPath } = options;
|
|
9
|
+
const httpRequest = options.httpRequest ?? http.request;
|
|
10
|
+
return function handle(req, res) {
|
|
11
|
+
if (!isAllowedRoute(req.method, req.url)) {
|
|
12
|
+
res.writeHead(404).end();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const chunks = [];
|
|
16
|
+
let received = 0;
|
|
17
|
+
let aborted = false;
|
|
18
|
+
req.on('data', (chunk) => {
|
|
19
|
+
if (aborted)
|
|
20
|
+
return;
|
|
21
|
+
received += chunk.length;
|
|
22
|
+
if (received > MAX_BODY_BYTES) {
|
|
23
|
+
aborted = true;
|
|
24
|
+
res.writeHead(413, { 'content-type': 'application/json' }).end(JSON.stringify({
|
|
25
|
+
error: 'request body exceeds 64 KiB',
|
|
26
|
+
code: 'PAYLOAD_TOO_LARGE',
|
|
27
|
+
}));
|
|
28
|
+
req.destroy();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
chunks.push(chunk);
|
|
32
|
+
});
|
|
33
|
+
req.on('end', () => {
|
|
34
|
+
if (aborted)
|
|
35
|
+
return;
|
|
36
|
+
const body = Buffer.concat(chunks);
|
|
37
|
+
const outboundHeaders = pickAllowedHeaders(req.headers);
|
|
38
|
+
outboundHeaders['content-length'] = String(body.length);
|
|
39
|
+
const upstreamReq = httpRequest({
|
|
40
|
+
socketPath: upstreamSocketPath,
|
|
41
|
+
method: 'POST',
|
|
42
|
+
path: '/git-token',
|
|
43
|
+
headers: outboundHeaders,
|
|
44
|
+
});
|
|
45
|
+
let settled = false;
|
|
46
|
+
const onFailure = (err) => {
|
|
47
|
+
if (settled)
|
|
48
|
+
return;
|
|
49
|
+
settled = true;
|
|
50
|
+
const code = mapUpstreamErrorToCode(err);
|
|
51
|
+
logUpstreamError({ code });
|
|
52
|
+
if (!res.headersSent) {
|
|
53
|
+
res.writeHead(502, { 'content-type': 'application/json' }).end(JSON.stringify({
|
|
54
|
+
error: 'control-plane upstream unreachable',
|
|
55
|
+
code,
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
res.end();
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
upstreamReq.setTimeout(UPSTREAM_TIMEOUT_MS, () => {
|
|
63
|
+
upstreamReq.destroy(new Error('timeout'));
|
|
64
|
+
});
|
|
65
|
+
upstreamReq.on('response', (upstreamRes) => {
|
|
66
|
+
if (settled)
|
|
67
|
+
return;
|
|
68
|
+
settled = true;
|
|
69
|
+
res.writeHead(upstreamRes.statusCode ?? 502, upstreamRes.headers);
|
|
70
|
+
upstreamRes.pipe(res);
|
|
71
|
+
upstreamRes.on('error', () => {
|
|
72
|
+
if (!res.writableEnded)
|
|
73
|
+
res.end();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
upstreamReq.on('error', onFailure);
|
|
77
|
+
upstreamReq.write(body);
|
|
78
|
+
upstreamReq.end();
|
|
79
|
+
});
|
|
80
|
+
req.on('error', () => {
|
|
81
|
+
if (!res.headersSent)
|
|
82
|
+
res.writeHead(400).end();
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/git-token-proxy/handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { isAllowedRoute, pickAllowedHeaders } from './allowlists.js';
|
|
2
|
+
export { mapUpstreamErrorToCode, type UpstreamErrorCode } from './upstream-errors.js';
|
|
3
|
+
export { logProxyInit, logUpstreamError } from './logging.js';
|
|
4
|
+
export { createHandler, MAX_BODY_BYTES, UPSTREAM_TIMEOUT_MS, type CreateHandlerOptions, type ProxyRequestHandler, } from './handler.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/git-token-proxy/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EACL,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,GACzB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { isAllowedRoute, pickAllowedHeaders } from './allowlists.js';
|
|
2
|
+
export { mapUpstreamErrorToCode } from './upstream-errors.js';
|
|
3
|
+
export { logProxyInit, logUpstreamError } from './logging.js';
|
|
4
|
+
export { createHandler, MAX_BODY_BYTES, UPSTREAM_TIMEOUT_MS, } from './handler.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/git-token-proxy/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAA0B,MAAM,sBAAsB,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EACL,aAAa,EACb,cAAc,EACd,mBAAmB,GAGpB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { UpstreamErrorCode } from './upstream-errors.js';
|
|
2
|
+
export declare function logProxyInit(args: {
|
|
3
|
+
listenSocket: string;
|
|
4
|
+
upstreamSocket: string;
|
|
5
|
+
}): void;
|
|
6
|
+
export declare function logUpstreamError(args: {
|
|
7
|
+
code: UpstreamErrorCode;
|
|
8
|
+
}): void;
|
|
9
|
+
//# sourceMappingURL=logging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../../src/git-token-proxy/logging.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,wBAAgB,YAAY,CAAC,IAAI,EAAE;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAQzF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,iBAAiB,CAAA;CAAE,GAAG,IAAI,CAOxE"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function logProxyInit(args) {
|
|
2
|
+
console.log(JSON.stringify({
|
|
3
|
+
event: 'git-token-proxy-init',
|
|
4
|
+
listenSocket: args.listenSocket,
|
|
5
|
+
upstreamSocket: args.upstreamSocket,
|
|
6
|
+
}));
|
|
7
|
+
}
|
|
8
|
+
export function logUpstreamError(args) {
|
|
9
|
+
console.log(JSON.stringify({
|
|
10
|
+
event: 'git-token-proxy-upstream-error',
|
|
11
|
+
code: args.code,
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=logging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.js","sourceRoot":"","sources":["../../../src/git-token-proxy/logging.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,YAAY,CAAC,IAAsD;IACjF,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CAAC;QACb,KAAK,EAAE,sBAAsB;QAC7B,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,cAAc,EAAE,IAAI,CAAC,cAAc;KACpC,CAAC,CACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAiC;IAChE,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CAAC;QACb,KAAK,EAAE,gCAAgC;QACvC,IAAI,EAAE,IAAI,CAAC,IAAI;KAChB,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The only upstream-side error code this bin emits. Single closed union: the
|
|
3
|
+
* CLI wrapper (#766) cares only that the upstream is unreachable; the per-
|
|
4
|
+
* request stdout log line tells operators which transport mode triggered it.
|
|
5
|
+
*/
|
|
6
|
+
export type UpstreamErrorCode = 'CONTROL_SOCKET_UNREACHABLE';
|
|
7
|
+
/**
|
|
8
|
+
* Collapses every upstream-transport failure (ECONNREFUSED, ENOENT,
|
|
9
|
+
* ECONNRESET, EPIPE, timeout/AbortError, generic Error, undefined) to the
|
|
10
|
+
* single error code. Identity-style mapper — a single source of truth so the
|
|
11
|
+
* handler never branches on errno strings inline.
|
|
12
|
+
*/
|
|
13
|
+
export declare function mapUpstreamErrorToCode(_err: unknown): UpstreamErrorCode;
|
|
14
|
+
//# sourceMappingURL=upstream-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upstream-errors.d.ts","sourceRoot":"","sources":["../../../src/git-token-proxy/upstream-errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,4BAA4B,CAAC;AAE7D;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,iBAAiB,CAEvE"}
|