@usine/gateway 0.0.0-stage → 0.2.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/LICENSE +661 -0
- package/README.md +200 -2
- package/dist/admin/api.d.ts +146 -0
- package/dist/admin/api.d.ts.map +1 -0
- package/dist/admin/api.js +105 -0
- package/dist/admin/api.js.map +1 -0
- package/dist/admin/server.d.ts +10 -0
- package/dist/admin/server.d.ts.map +1 -0
- package/dist/admin/server.js +79 -0
- package/dist/admin/server.js.map +1 -0
- package/dist/attachment/attachment.d.ts +84 -0
- package/dist/attachment/attachment.d.ts.map +1 -0
- package/dist/attachment/attachment.js +67 -0
- package/dist/attachment/attachment.js.map +1 -0
- package/dist/attachment/store.d.ts +34 -0
- package/dist/attachment/store.d.ts.map +1 -0
- package/dist/attachment/store.js +133 -0
- package/dist/attachment/store.js.map +1 -0
- package/dist/caller/caller.d.ts +60 -0
- package/dist/caller/caller.d.ts.map +1 -0
- package/dist/caller/caller.js +131 -0
- package/dist/caller/caller.js.map +1 -0
- package/dist/chatgpt/auth-file.d.ts +47 -0
- package/dist/chatgpt/auth-file.d.ts.map +1 -0
- package/dist/chatgpt/auth-file.js +132 -0
- package/dist/chatgpt/auth-file.js.map +1 -0
- package/dist/chatgpt/logins.d.ts +50 -0
- package/dist/chatgpt/logins.d.ts.map +1 -0
- package/dist/chatgpt/logins.js +303 -0
- package/dist/chatgpt/logins.js.map +1 -0
- package/dist/egress/client-hello.d.ts +120 -0
- package/dist/egress/client-hello.d.ts.map +1 -0
- package/dist/egress/client-hello.js +155 -0
- package/dist/egress/client-hello.js.map +1 -0
- package/dist/egress/egress.d.ts +66 -0
- package/dist/egress/egress.d.ts.map +1 -0
- package/dist/egress/egress.js +114 -0
- package/dist/egress/egress.js.map +1 -0
- package/dist/gateway.d.ts +27 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +27 -0
- package/dist/gateway.js.map +1 -0
- package/dist/github/github.d.ts +54 -0
- package/dist/github/github.d.ts.map +1 -0
- package/dist/github/github.js +112 -0
- package/dist/github/github.js.map +1 -0
- package/dist/github/rename.d.ts +30 -0
- package/dist/github/rename.d.ts.map +1 -0
- package/dist/github/rename.js +83 -0
- package/dist/github/rename.js.map +1 -0
- package/dist/llm/llm.d.ts +113 -0
- package/dist/llm/llm.d.ts.map +1 -0
- package/dist/llm/llm.js +144 -0
- package/dist/llm/llm.js.map +1 -0
- package/dist/node/egress-proxy.d.ts +30 -0
- package/dist/node/egress-proxy.d.ts.map +1 -0
- package/dist/node/egress-proxy.js +491 -0
- package/dist/node/egress-proxy.js.map +1 -0
- package/dist/node/environment.d.ts +113 -0
- package/dist/node/environment.d.ts.map +1 -0
- package/dist/node/environment.js +140 -0
- package/dist/node/environment.js.map +1 -0
- package/dist/node/main.d.ts +3 -0
- package/dist/node/main.d.ts.map +1 -0
- package/dist/node/main.js +13 -0
- package/dist/node/main.js.map +1 -0
- package/dist/node/node.d.ts +28 -0
- package/dist/node/node.d.ts.map +1 -0
- package/dist/node/node.js +81 -0
- package/dist/node/node.js.map +1 -0
- package/dist/node/reload.d.ts +27 -0
- package/dist/node/reload.d.ts.map +1 -0
- package/dist/node/reload.js +170 -0
- package/dist/node/reload.js.map +1 -0
- package/dist/proxy/forward.d.ts +12 -0
- package/dist/proxy/forward.d.ts.map +1 -0
- package/dist/proxy/forward.js +44 -0
- package/dist/proxy/forward.js.map +1 -0
- package/dist/proxy/proxy.d.ts +29 -0
- package/dist/proxy/proxy.d.ts.map +1 -0
- package/dist/proxy/proxy.js +297 -0
- package/dist/proxy/proxy.js.map +1 -0
- package/dist/settings.d.ts +52 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +27 -0
- package/dist/settings.js.map +1 -0
- package/dist/upstream.d.ts +5 -0
- package/dist/upstream.d.ts.map +1 -0
- package/dist/upstream.js +6 -0
- package/dist/upstream.js.map +1 -0
- package/package.json +58 -3
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Schema } from "effect";
|
|
2
|
+
import { HttpClient, HttpServerRequest, HttpServerResponse } from "effect/http";
|
|
3
|
+
import { Attachments } from "../attachment/store.ts";
|
|
4
|
+
import { CallerTokens } from "../caller/caller.ts";
|
|
5
|
+
import { ChatGptLogins } from "../chatgpt/logins.ts";
|
|
6
|
+
import { GatewaySettings, SettingsInForce } from "../settings.ts";
|
|
7
|
+
/**
|
|
8
|
+
* The reason the Gateway refused a request. Each refusal is logged at warning level with the
|
|
9
|
+
* reason, host, and Worker (if known), and returned in `x-usine-gateway-refusal`.
|
|
10
|
+
*/
|
|
11
|
+
export declare const RefusalReason: Schema.Literals<readonly ["unknown-host", "unsupported-path", "missing-caller-token", "invalid-caller-token", "stale-caller-token", "attachment-expired", "repository-mismatch", "provider-not-configured", "provider-login-unavailable"]>;
|
|
12
|
+
export type RefusalReason = typeof RefusalReason.Type;
|
|
13
|
+
/** The response header that contains the refusal reason. */
|
|
14
|
+
export declare const REFUSAL_HEADER = "x-usine-gateway-refusal";
|
|
15
|
+
declare const GatewayProxy_base: Context.ServiceClass<GatewayProxy, "@usine/gateway/GatewayProxy", {
|
|
16
|
+
/** Forwards one Worker request with the attached credential, or refuses and logs it. */
|
|
17
|
+
readonly handle: Effect.Effect<HttpServerResponse.HttpServerResponse, never, HttpServerRequest.HttpServerRequest>;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* The reverse proxy for Worker VMs on the private network. `git.<domain>` serves GitHub with
|
|
21
|
+
* the attached installation token, and `llm.<domain>` serves the LLM providers with the
|
|
22
|
+
* current credentials. Every request must have a caller token for an active attachment; other
|
|
23
|
+
* hosts are refused.
|
|
24
|
+
*/
|
|
25
|
+
export declare class GatewayProxy extends GatewayProxy_base {
|
|
26
|
+
static readonly layer: Layer.Layer<GatewayProxy, never, Attachments | CallerTokens | ChatGptLogins | GatewaySettings | HttpClient.HttpClient | SettingsInForce>;
|
|
27
|
+
}
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/proxy/proxy.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAQ,MAAM,EAAE,KAAK,EAAyB,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrF,OAAO,EAEL,UAAU,EAEV,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAEL,YAAY,EAGb,MAAM,qBAAqB,CAAC;AAW7B,OAAO,EAAgC,aAAa,EAAE,MAAM,sBAAsB,CAAC;AASnF,OAAO,EAAE,eAAe,EAAgB,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGhF;;;GAGG;AACH,eAAO,MAAM,aAAa,4OAUxB,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAC,IAAI,CAAC;AAEtD,4DAA4D;AAC5D,eAAO,MAAM,cAAc,4BAA4B,CAAC;;IA4EpD,wFAAwF;qBACvE,MAAM,CAAC,MAAM,CAC5B,kBAAkB,CAAC,kBAAkB,EACrC,KAAK,EACL,iBAAiB,CAAC,iBAAiB,CACpC;;AAdL;;;;;GAKG;AACH,qBAAa,YAAa,SAAQ,iBAUA;IAChC,MAAM,CAAC,QAAQ,CAAC,KAAK,2IAiSnB;CACH"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { canonicalRepositoryName } from "@usine/core/repository";
|
|
2
|
+
import { Context, Data, Effect, Layer, Match, Option, Result, Schema } from "effect";
|
|
3
|
+
import { Headers, HttpClient, HttpServerRequest, HttpServerResponse, } from "effect/http";
|
|
4
|
+
import { Attachments } from "../attachment/store.js";
|
|
5
|
+
import { CallerTokens, presentedToken, withoutCallerCredentials, } from "../caller/caller.js";
|
|
6
|
+
import { absoluteUrl, GITHUB_HOSTS, gatewayLocation, githubRoute, withGitHubCredential, } from "../github/github.js";
|
|
7
|
+
import { confirmRename, PERMANENT_REDIRECTS, redirectedName } from "../github/rename.js";
|
|
8
|
+
import { ChatGptLogins } from "../chatgpt/logins.js";
|
|
9
|
+
import { llmRoute, configuredProvider, llmTarget, withChatGptAccess, withStaticCredential, } from "../llm/llm.js";
|
|
10
|
+
import { GatewaySettings, gatewayHosts, SettingsInForce } from "../settings.js";
|
|
11
|
+
import { endToEndHeaders, forwardRequest } from "./forward.js";
|
|
12
|
+
/**
|
|
13
|
+
* The reason the Gateway refused a request. Each refusal is logged at warning level with the
|
|
14
|
+
* reason, host, and Worker (if known), and returned in `x-usine-gateway-refusal`.
|
|
15
|
+
*/
|
|
16
|
+
export const RefusalReason = Schema.Literals([
|
|
17
|
+
"unknown-host",
|
|
18
|
+
"unsupported-path",
|
|
19
|
+
"missing-caller-token",
|
|
20
|
+
"invalid-caller-token",
|
|
21
|
+
"stale-caller-token",
|
|
22
|
+
"attachment-expired",
|
|
23
|
+
"repository-mismatch",
|
|
24
|
+
"provider-not-configured",
|
|
25
|
+
"provider-login-unavailable",
|
|
26
|
+
]);
|
|
27
|
+
/** The response header that contains the refusal reason. */
|
|
28
|
+
export const REFUSAL_HEADER = "x-usine-gateway-refusal";
|
|
29
|
+
const REFUSAL_STATUS = {
|
|
30
|
+
"unknown-host": 404,
|
|
31
|
+
"unsupported-path": 404,
|
|
32
|
+
"missing-caller-token": 401,
|
|
33
|
+
"invalid-caller-token": 401,
|
|
34
|
+
"stale-caller-token": 403,
|
|
35
|
+
"attachment-expired": 403,
|
|
36
|
+
"repository-mismatch": 403,
|
|
37
|
+
"provider-not-configured": 503,
|
|
38
|
+
"provider-login-unavailable": 503,
|
|
39
|
+
};
|
|
40
|
+
/** A refusal, with the caller's claims once its token is verified, and the response status. */
|
|
41
|
+
class Refused extends Data.TaggedError("Refused") {
|
|
42
|
+
}
|
|
43
|
+
/** Returns a refusal for a request whose caller token isn't verified yet. */
|
|
44
|
+
const refused = (reason, message) => new Refused({ reason, message, caller: Option.none(), status: REFUSAL_STATUS[reason] });
|
|
45
|
+
/** Returns a refusal for a verified caller. */
|
|
46
|
+
const refusedCaller = (claims, reason, message) => new Refused({ reason, message, caller: Option.some(claims), status: REFUSAL_STATUS[reason] });
|
|
47
|
+
/**
|
|
48
|
+
* Returns the refusal for a ChatGPT login without a usable access token: 503 while a later
|
|
49
|
+
* refresh can succeed, which Codex retries, and 401 once the token endpoint has rejected the
|
|
50
|
+
* refresh token, which Codex doesn't.
|
|
51
|
+
*/
|
|
52
|
+
const loginUnavailable = (claims, error) => new Refused({
|
|
53
|
+
reason: "provider-login-unavailable",
|
|
54
|
+
message: error.message,
|
|
55
|
+
caller: Option.some(claims),
|
|
56
|
+
status: error.reason === "refresh-rejected" ? 401 : 503,
|
|
57
|
+
});
|
|
58
|
+
/** Returns the target from an origin-form request and its `Host`, or from an absolute-form URL. */
|
|
59
|
+
const requestTarget = (request) => {
|
|
60
|
+
const parse = (base) => Result.getSuccess(Result.try(() => new URL(request.url, base)));
|
|
61
|
+
return parse().pipe(Option.orElse(() => Option.flatMap(Headers.get(request.headers, "host"), (host) => parse(`http://${host}`))), Option.map((url) => ({
|
|
62
|
+
host: url.hostname.toLowerCase(),
|
|
63
|
+
pathname: url.pathname,
|
|
64
|
+
search: url.search,
|
|
65
|
+
})));
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* The reverse proxy for Worker VMs on the private network. `git.<domain>` serves GitHub with
|
|
69
|
+
* the attached installation token, and `llm.<domain>` serves the LLM providers with the
|
|
70
|
+
* current credentials. Every request must have a caller token for an active attachment; other
|
|
71
|
+
* hosts are refused.
|
|
72
|
+
*/
|
|
73
|
+
export class GatewayProxy extends Context.Service()("@usine/gateway/GatewayProxy") {
|
|
74
|
+
static layer = Layer.effect(GatewayProxy, Effect.gen(function* () {
|
|
75
|
+
const settings = yield* GatewaySettings;
|
|
76
|
+
const inForce = yield* SettingsInForce;
|
|
77
|
+
const attachments = yield* Attachments;
|
|
78
|
+
const callers = yield* CallerTokens;
|
|
79
|
+
const logins = yield* ChatGptLogins;
|
|
80
|
+
const client = yield* HttpClient.HttpClient;
|
|
81
|
+
const hosts = gatewayHosts(settings.domain);
|
|
82
|
+
const authenticate = Effect.fn("GatewayProxy.authenticate")(function* (request) {
|
|
83
|
+
const presented = presentedToken(request.headers);
|
|
84
|
+
if (Option.isNone(presented))
|
|
85
|
+
return yield* refused("missing-caller-token", "The request has no gateway caller token.");
|
|
86
|
+
const claims = yield* callers
|
|
87
|
+
.verify(presented.value)
|
|
88
|
+
.pipe(Effect.mapError(({ reason }) => refused("invalid-caller-token", `The gateway didn't issue this caller token (${reason}).`)));
|
|
89
|
+
yield* Effect.annotateCurrentSpan({
|
|
90
|
+
attachment: claims.attachment,
|
|
91
|
+
worker: claims.worker,
|
|
92
|
+
repository: claims.repository,
|
|
93
|
+
});
|
|
94
|
+
const stale = refusedCaller(claims, "stale-caller-token", `The caller token belongs to attachment ${claims.attachment} of ${claims.repository} on worker "${claims.worker}", which is no longer attached.`);
|
|
95
|
+
const lookup = yield* attachments.find(claims.attachment);
|
|
96
|
+
return yield* Match.valueTags(lookup, {
|
|
97
|
+
LiveAttachment: (live) => live.attachment.worker === claims.worker &&
|
|
98
|
+
canonicalRepositoryName(live.attachment.repository) ===
|
|
99
|
+
canonicalRepositoryName(claims.repository)
|
|
100
|
+
? Effect.succeed({ claims, live })
|
|
101
|
+
: Effect.fail(stale),
|
|
102
|
+
ExpiredAttachment: () => Effect.fail(refusedCaller(claims, "attachment-expired", `The attachment of ${claims.repository} to worker "${claims.worker}" has expired.`)),
|
|
103
|
+
MissingAttachment: () => Effect.fail(stale),
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
/**
|
|
107
|
+
* Teaches the attachment the new name in GitHub's permanent redirect of a request for the
|
|
108
|
+
* repository itself, once GitHub's API confirms it with the attachment's credential. GitHub
|
|
109
|
+
* answers a renamed or transferred repository's former name that way; a redirect of anything
|
|
110
|
+
* else can point at another repository without a rename.
|
|
111
|
+
*/
|
|
112
|
+
const learnFromRedirect = Effect.fn("GatewayProxy.learnFromRedirect")(function* (live, requested, location) {
|
|
113
|
+
const { attachment } = live;
|
|
114
|
+
yield* Effect.annotateCurrentSpan({
|
|
115
|
+
attachment: attachment.id,
|
|
116
|
+
repository: attachment.repository,
|
|
117
|
+
});
|
|
118
|
+
const fields = {
|
|
119
|
+
attachment: attachment.id,
|
|
120
|
+
worker: attachment.worker,
|
|
121
|
+
repository: attachment.repository,
|
|
122
|
+
};
|
|
123
|
+
const newName = Option.flatMap(absoluteUrl(requested.upstream), (upstream) => redirectedName(settings.github, upstream, location));
|
|
124
|
+
if (Option.isNone(newName))
|
|
125
|
+
return yield* Effect.logDebug("Learned no name from a redirect that isn't a rename", {
|
|
126
|
+
...fields,
|
|
127
|
+
path: location.pathname,
|
|
128
|
+
});
|
|
129
|
+
const renamed = { ...fields, newName: newName.value };
|
|
130
|
+
if (live.serves(newName.value))
|
|
131
|
+
return yield* Effect.logDebug("The attachment already serves the redirect's name", renamed);
|
|
132
|
+
yield* confirmRename(client, settings.github, attachment, newName.value).pipe(Effect.andThen(attachments.learnNewName(attachment.id, newName.value)), Effect.catchTag("RenameUnconfirmed", ({ reason, detail }) => Effect.logWarning("GitHub's API didn't confirm the new name of an attached repository", {
|
|
133
|
+
...renamed,
|
|
134
|
+
reason,
|
|
135
|
+
detail,
|
|
136
|
+
})));
|
|
137
|
+
});
|
|
138
|
+
/** Points a `Location` at github.com or api.github.com to `git.<domain>`, and logs the rewrite. */
|
|
139
|
+
const throughGateway = Effect.fn("GatewayProxy.throughGateway")(function* (answer, live, requested) {
|
|
140
|
+
const { attachment } = live;
|
|
141
|
+
const from = Option.flatMap(Headers.get(answer.headers, "location"), absoluteUrl);
|
|
142
|
+
const to = Option.flatMap(from, (url) => gatewayLocation(settings.github, hosts.git, url));
|
|
143
|
+
if (Option.isNone(from) || Option.isNone(to))
|
|
144
|
+
return answer;
|
|
145
|
+
yield* Effect.logInfo("Rewrote a GitHub Location header to the gateway", {
|
|
146
|
+
worker: attachment.worker,
|
|
147
|
+
repository: attachment.repository,
|
|
148
|
+
status: answer.status,
|
|
149
|
+
from: from.value.host,
|
|
150
|
+
path: to.value.pathname,
|
|
151
|
+
});
|
|
152
|
+
if (PERMANENT_REDIRECTS.has(answer.status))
|
|
153
|
+
yield* learnFromRedirect(live, requested, from.value);
|
|
154
|
+
return HttpServerResponse.setHeader(answer, "location", to.value.href);
|
|
155
|
+
});
|
|
156
|
+
const github = Effect.fn("GatewayProxy.github")(function* (request, target, host) {
|
|
157
|
+
const { claims, live } = yield* authenticate(request);
|
|
158
|
+
const { attachment } = live;
|
|
159
|
+
const route = githubRoute(settings.github, host, target.pathname, target.search);
|
|
160
|
+
if (Option.isNone(route))
|
|
161
|
+
return yield* refusedCaller(claims, "unsupported-path", `The gateway serves Git smart HTTP, release downloads, and the GitHub API, not ${target.pathname}.`);
|
|
162
|
+
const named = route.value.repository;
|
|
163
|
+
if (Option.isSome(named) && !live.serves(named.value))
|
|
164
|
+
return yield* refusedCaller(claims, "repository-mismatch", `The caller token was issued for ${claims.repository}, not ${named.value}.`);
|
|
165
|
+
const headers = withGitHubCredential(route.value.protocol, attachment.credential, withoutCallerCredentials(endToEndHeaders(request.headers)));
|
|
166
|
+
const response = yield* throughGateway(yield* forwardRequest(client, request, route.value.upstream, headers), live, route.value);
|
|
167
|
+
yield* forwarded(route.value.protocol === "release"
|
|
168
|
+
? "Served a GitHub release download"
|
|
169
|
+
: "Forwarded a GitHub request", request, target, attachment, response, { protocol: route.value.protocol, ...redirectTarget(response) });
|
|
170
|
+
return response;
|
|
171
|
+
});
|
|
172
|
+
const llm = Effect.fn("GatewayProxy.llm")(function* (request, target) {
|
|
173
|
+
const { claims, live: { attachment }, } = yield* authenticate(request);
|
|
174
|
+
const destination = llmTarget(target.pathname);
|
|
175
|
+
if (Option.isNone(destination))
|
|
176
|
+
return yield* refusedCaller(claims, "unsupported-path", `The gateway serves /anthropic and /openai on ${hosts.llm}, not ${target.pathname}.`);
|
|
177
|
+
const { providers } = yield* inForce.current;
|
|
178
|
+
const provider = configuredProvider(providers, destination.value.provider);
|
|
179
|
+
if (Option.isNone(provider))
|
|
180
|
+
return yield* refusedCaller(claims, "provider-not-configured", `The gateway has no credential for ${destination.value.provider}.`);
|
|
181
|
+
const path = llmRoute(provider.value, destination.value.rest);
|
|
182
|
+
if (Option.isNone(path))
|
|
183
|
+
return yield* refusedCaller(claims, "unsupported-path", `The gateway serves only the routes Claude Code and Codex call on ${hosts.llm}, such as /anthropic/v1/messages and /openai/v1/responses, not ${target.pathname}.`);
|
|
184
|
+
const incoming = withoutCallerCredentials(endToEndHeaders(request.headers));
|
|
185
|
+
const { credential } = provider.value;
|
|
186
|
+
const outgoing = credential._tag === "ChatGptLogin"
|
|
187
|
+
? yield* chatGptRequest(claims, credential, incoming)
|
|
188
|
+
: {
|
|
189
|
+
headers: withStaticCredential(credential, incoming),
|
|
190
|
+
answered: () => Effect.void,
|
|
191
|
+
};
|
|
192
|
+
const upstream = `${provider.value.upstream}${path.value}${target.search}`;
|
|
193
|
+
const response = yield* forwardRequest(client, request, upstream, outgoing.headers);
|
|
194
|
+
yield* outgoing.answered(response.status);
|
|
195
|
+
yield* forwarded("Forwarded an LLM request", request, target, attachment, response, {
|
|
196
|
+
provider: destination.value.provider,
|
|
197
|
+
credential: credential._tag,
|
|
198
|
+
});
|
|
199
|
+
return response;
|
|
200
|
+
});
|
|
201
|
+
/**
|
|
202
|
+
* Returns the headers for a request with a ChatGPT login, and records a 401 answer so the
|
|
203
|
+
* next request refreshes the access token first.
|
|
204
|
+
*/
|
|
205
|
+
const chatGptRequest = Effect.fn("GatewayProxy.chatGptRequest")(function* (claims, login, incoming) {
|
|
206
|
+
const access = yield* logins
|
|
207
|
+
.access(login)
|
|
208
|
+
.pipe(Effect.mapError((error) => loginUnavailable(claims, error)));
|
|
209
|
+
return {
|
|
210
|
+
headers: withChatGptAccess(access, incoming),
|
|
211
|
+
answered: (status) => status === 401 ? logins.refused(login, access) : Effect.void,
|
|
212
|
+
};
|
|
213
|
+
});
|
|
214
|
+
/**
|
|
215
|
+
* Refuses a host the reverse proxy doesn't serve. gh sends every request to the gateway,
|
|
216
|
+
* including a followed redirect to a GitHub download host, so for an allowlisted host the
|
|
217
|
+
* refusal says how to download from it with curl.
|
|
218
|
+
*/
|
|
219
|
+
const unknownHost = Effect.fn("GatewayProxy.unknownHost")(function* (target) {
|
|
220
|
+
const { egress } = yield* inForce.current;
|
|
221
|
+
const served = `The gateway serves ${hosts.git} and ${hosts.llm}, not ${target.host}`;
|
|
222
|
+
return yield* refused("unknown-host", egress.decide(target.host, 443)._tag === "EgressPermitted"
|
|
223
|
+
? `${served}, which the forward proxy serves. gh sends every request to the gateway, so it can't follow GitHub's redirect to ${target.host}. Download with curl -fL -u ":$GH_TOKEN" from ${hosts.git} instead, such as http://${hosts.git}/OWNER/REPO/releases/download/TAG/FILE, or http://${hosts.git}/api/v3/repos/OWNER/REPO/tarball/REF for an archive.`
|
|
224
|
+
: `${served}. Send requests for other hosts through the forward proxy.`);
|
|
225
|
+
});
|
|
226
|
+
const route = (request, target) => {
|
|
227
|
+
if (target.host === hosts.git)
|
|
228
|
+
return github(request, target, "gateway");
|
|
229
|
+
const githubHost = GITHUB_HOSTS.get(target.host);
|
|
230
|
+
if (githubHost !== undefined)
|
|
231
|
+
return github(request, target, githubHost);
|
|
232
|
+
if (target.host === hosts.llm)
|
|
233
|
+
return llm(request, target);
|
|
234
|
+
return unknownHost(target);
|
|
235
|
+
};
|
|
236
|
+
const handle = Effect.gen(function* () {
|
|
237
|
+
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
238
|
+
const target = requestTarget(request);
|
|
239
|
+
if (Option.isNone(target)) {
|
|
240
|
+
const error = refused("unknown-host", "The request has no host.");
|
|
241
|
+
yield* Effect.logWarning("Gateway refused a request", {
|
|
242
|
+
reason: error.reason,
|
|
243
|
+
method: request.method,
|
|
244
|
+
client: clientAddress(request),
|
|
245
|
+
});
|
|
246
|
+
return refusalResponse(error);
|
|
247
|
+
}
|
|
248
|
+
yield* Effect.annotateCurrentSpan({ host: target.value.host, method: request.method });
|
|
249
|
+
return yield* route(request, target.value).pipe(Effect.catchTags({
|
|
250
|
+
Refused: (error) => logRefusal(request, target.value, error).pipe(Effect.as(refusalResponse(error))),
|
|
251
|
+
HttpClientError: (error) => upstreamFailure(request, target.value, error),
|
|
252
|
+
}));
|
|
253
|
+
}).pipe(Effect.withSpan("GatewayProxy.handle"));
|
|
254
|
+
return { handle };
|
|
255
|
+
}));
|
|
256
|
+
}
|
|
257
|
+
const refusalResponse = (error) => HttpServerResponse.jsonUnsafe({ message: `usine gateway: ${error.message}`, reason: error.reason }, { status: error.status, headers: { [REFUSAL_HEADER]: error.reason } });
|
|
258
|
+
/** Returns the host a response redirects to, without the `Location` path and query, which can hold a signature. */
|
|
259
|
+
const redirectTarget = (response) => Option.match(Option.flatMap(Headers.get(response.headers, "location"), absoluteUrl), {
|
|
260
|
+
onNone: () => ({}),
|
|
261
|
+
onSome: (url) => ({ target: url.host }),
|
|
262
|
+
});
|
|
263
|
+
const clientAddress = (request) => Option.getOrElse(request.remoteAddress, () => "unknown");
|
|
264
|
+
const logRefusal = (request, target, error) => {
|
|
265
|
+
const caller = Option.match(error.caller, {
|
|
266
|
+
onNone: () => ({ caller: "unverified" }),
|
|
267
|
+
onSome: ({ worker, repository }) => ({ worker, repository }),
|
|
268
|
+
});
|
|
269
|
+
return Effect.logWarning("Gateway refused a request", {
|
|
270
|
+
reason: error.reason,
|
|
271
|
+
host: target.host,
|
|
272
|
+
method: request.method,
|
|
273
|
+
path: target.pathname,
|
|
274
|
+
client: clientAddress(request),
|
|
275
|
+
...caller,
|
|
276
|
+
});
|
|
277
|
+
};
|
|
278
|
+
const forwarded = (message, request, target, attachment, response, detail) => Effect.logInfo(message, {
|
|
279
|
+
...detail,
|
|
280
|
+
worker: attachment.worker,
|
|
281
|
+
repository: attachment.repository,
|
|
282
|
+
host: target.host,
|
|
283
|
+
method: request.method,
|
|
284
|
+
path: target.pathname,
|
|
285
|
+
status: response.status,
|
|
286
|
+
});
|
|
287
|
+
const upstreamFailure = (request, target, error) => Effect.logError("The upstream of a Worker request could not be reached", {
|
|
288
|
+
host: target.host,
|
|
289
|
+
method: request.method,
|
|
290
|
+
path: target.pathname,
|
|
291
|
+
client: clientAddress(request),
|
|
292
|
+
error: error.reason._tag,
|
|
293
|
+
}).pipe(Effect.as(HttpServerResponse.jsonUnsafe({
|
|
294
|
+
message: "usine gateway: the upstream is unreachable.",
|
|
295
|
+
reason: "upstream-unreachable",
|
|
296
|
+
}, { status: 502 })));
|
|
297
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/proxy/proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { GatewayDomain } from "@usine/core/worker";
|
|
2
|
+
import { Context, Effect, Layer, Schema } from "effect";
|
|
3
|
+
import type { EgressAllowlist } from "./egress/egress.ts";
|
|
4
|
+
import type { GitHubOrigins } from "./github/github.ts";
|
|
5
|
+
import type { LlmProviders } from "./llm/llm.ts";
|
|
6
|
+
/** The HMAC key that signs caller tokens, at least 32 characters, known only to the Gateway. */
|
|
7
|
+
export declare const CallerKey: Schema.RedactedFromValue<Schema.String>;
|
|
8
|
+
export type CallerKey = typeof CallerKey.Type;
|
|
9
|
+
/** The bearer token the executor sends to the admin API, at least 32 characters. */
|
|
10
|
+
export declare const AdminToken: Schema.RedactedFromValue<Schema.String>;
|
|
11
|
+
export type AdminToken = typeof AdminToken.Type;
|
|
12
|
+
declare const GatewaySettings_base: Context.ServiceClass<GatewaySettings, "@usine/gateway/GatewaySettings", {
|
|
13
|
+
readonly domain: GatewayDomain;
|
|
14
|
+
readonly github: GitHubOrigins;
|
|
15
|
+
readonly providers: LlmProviders;
|
|
16
|
+
readonly egress: EgressAllowlist;
|
|
17
|
+
readonly adminToken: AdminToken;
|
|
18
|
+
readonly callerKey: CallerKey;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* The Gateway's configuration as read at startup. Secrets stay `Redacted` until sent or used to
|
|
22
|
+
* sign. `egress` and `providers` keep their startup values; reloaded values are in
|
|
23
|
+
* `SettingsInForce`. Other settings change only with a restart.
|
|
24
|
+
*/
|
|
25
|
+
export declare class GatewaySettings extends GatewaySettings_base {
|
|
26
|
+
}
|
|
27
|
+
/** The settings a reload replaces: the egress allowlist and LLM providers. */
|
|
28
|
+
export interface ReloadableSettings {
|
|
29
|
+
readonly egress: EgressAllowlist;
|
|
30
|
+
readonly providers: LlmProviders;
|
|
31
|
+
}
|
|
32
|
+
declare const SettingsInForce_base: Context.ServiceClass<SettingsInForce, "@usine/gateway/SettingsInForce", {
|
|
33
|
+
/** Returns the current allowlist and providers. */
|
|
34
|
+
readonly current: Effect.Effect<ReloadableSettings>;
|
|
35
|
+
/** Replaces them for all later requests. */
|
|
36
|
+
readonly replace: (next: ReloadableSettings) => Effect.Effect<void>;
|
|
37
|
+
}>;
|
|
38
|
+
/**
|
|
39
|
+
* The current egress allowlist and LLM providers, initially from `GatewaySettings` and
|
|
40
|
+
* replaced by each reload. A request reads them once, so a tunnel opened under the previous
|
|
41
|
+
* allowlist stays open.
|
|
42
|
+
*/
|
|
43
|
+
export declare class SettingsInForce extends SettingsInForce_base {
|
|
44
|
+
static readonly layer: Layer.Layer<SettingsInForce, never, GatewaySettings>;
|
|
45
|
+
}
|
|
46
|
+
/** Returns the host names the Gateway serves under `domain`. */
|
|
47
|
+
export declare const gatewayHosts: (domain: GatewayDomain) => {
|
|
48
|
+
readonly git: `git.${string & import("effect/Brand").Brand<"GatewayDomain">}`;
|
|
49
|
+
readonly llm: `llm.${string & import("effect/Brand").Brand<"GatewayDomain">}`;
|
|
50
|
+
};
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAO,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,gGAAgG;AAChG,eAAO,MAAM,SAAS,yCAIrB,CAAC;AACF,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAC;AAE9C,oFAAoF;AACpF,eAAO,MAAM,UAAU,yCAItB,CAAC;AACF,MAAM,MAAM,UAAU,GAAG,OAAO,UAAU,CAAC,IAAI,CAAC;;qBAU3B,aAAa;qBACb,aAAa;wBACV,YAAY;qBACf,eAAe;yBACX,UAAU;wBACX,SAAS;;AAbjC;;;;GAIG;AACH,qBAAa,eAAgB,SAAQ,oBAUA;CAAG;AAExC,8EAA8E;AAC9E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;CAClC;;IAUG,mDAAmD;sBACjC,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC;IACnD,4CAA4C;sBAC1B,CAAC,IAAI,EAAE,kBAAkB,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;;AAXvE;;;;GAIG;AACH,qBAAa,eAAgB,SAAQ,oBAQA;IACnC,MAAM,CAAC,QAAQ,CAAC,KAAK,uDAOnB;CACH;AAED,gEAAgE;AAChE,eAAO,MAAM,YAAY,WAAY,aAAa;aAC7C,GAAG;aAAmB,GAAG;CAA6B,CAAC"}
|
package/dist/settings.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Ref, Schema } from "effect";
|
|
2
|
+
/** The HMAC key that signs caller tokens, at least 32 characters, known only to the Gateway. */
|
|
3
|
+
export const CallerKey = Schema.RedactedFromValue(Schema.String.check(Schema.isMinLength(32, { message: "Expected a caller key of at least 32 characters" })));
|
|
4
|
+
/** The bearer token the executor sends to the admin API, at least 32 characters. */
|
|
5
|
+
export const AdminToken = Schema.RedactedFromValue(Schema.String.check(Schema.isMinLength(32, { message: "Expected an admin token of at least 32 characters" })));
|
|
6
|
+
/**
|
|
7
|
+
* The Gateway's configuration as read at startup. Secrets stay `Redacted` until sent or used to
|
|
8
|
+
* sign. `egress` and `providers` keep their startup values; reloaded values are in
|
|
9
|
+
* `SettingsInForce`. Other settings change only with a restart.
|
|
10
|
+
*/
|
|
11
|
+
export class GatewaySettings extends Context.Service()("@usine/gateway/GatewaySettings") {
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The current egress allowlist and LLM providers, initially from `GatewaySettings` and
|
|
15
|
+
* replaced by each reload. A request reads them once, so a tunnel opened under the previous
|
|
16
|
+
* allowlist stays open.
|
|
17
|
+
*/
|
|
18
|
+
export class SettingsInForce extends Context.Service()("@usine/gateway/SettingsInForce") {
|
|
19
|
+
static layer = Layer.effect(SettingsInForce, Effect.gen(function* () {
|
|
20
|
+
const { egress, providers } = yield* GatewaySettings;
|
|
21
|
+
const inForce = yield* Ref.make({ egress, providers });
|
|
22
|
+
return { current: Ref.get(inForce), replace: (next) => Ref.set(inForce, next) };
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
/** Returns the host names the Gateway serves under `domain`. */
|
|
26
|
+
export const gatewayHosts = (domain) => ({ git: `git.${domain}`, llm: `llm.${domain}` });
|
|
27
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAK7D,gGAAgG;AAChG,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC,iBAAiB,CAC/C,MAAM,CAAC,MAAM,CAAC,KAAK,CACjB,MAAM,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,iDAAiD,EAAE,CAAC,CACvF,CACF,CAAC;AAGF,oFAAoF;AACpF,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,iBAAiB,CAChD,MAAM,CAAC,MAAM,CAAC,KAAK,CACjB,MAAM,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,mDAAmD,EAAE,CAAC,CACzF,CACF,CAAC;AAGF;;;;GAIG;AACH,MAAM,OAAO,eAAgB,SAAQ,OAAO,CAAC,OAAO,EAUjD,CAAC,gCAAgC,CAAC;CAAG;AAQxC;;;;GAIG;AACH,MAAM,OAAO,eAAgB,SAAQ,OAAO,CAAC,OAAO,EAQjD,CAAC,gCAAgC,CAAC;IACnC,MAAM,CAAU,KAAK,GAAG,KAAK,CAAC,MAAM,CAClC,eAAe,EACf,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC,CAAC,eAAe,CAAC;QACrD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAqB,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAC3E,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;IAClF,CAAC,CAAC,CACH,CAAC;CACH;AAED,gEAAgE;AAChE,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAqB,EAAE,EAAE,CACpD,CAAC,EAAE,GAAG,EAAE,OAAO,MAAM,EAAE,EAAE,GAAG,EAAE,OAAO,MAAM,EAAE,EAAE,CAAU,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
/** The base URL of an upstream API: scheme, host, and an optional path prefix, with no query, fragment, or trailing slash. */
|
|
3
|
+
export declare const UpstreamBase: Schema.brand<Schema.String, "UpstreamBase">;
|
|
4
|
+
export type UpstreamBase = typeof UpstreamBase.Type;
|
|
5
|
+
//# sourceMappingURL=upstream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upstream.d.ts","sourceRoot":"","sources":["../src/upstream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,8HAA8H;AAC9H,eAAO,MAAM,YAAY,6CAIW,CAAC;AACrC,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAC"}
|
package/dist/upstream.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
/** The base URL of an upstream API: scheme, host, and an optional path prefix, with no query, fragment, or trailing slash. */
|
|
3
|
+
export const UpstreamBase = Schema.String.check(Schema.isPattern(/^https?:\/\/[^/?#\s]+(?:\/[^?#\s]*[^/?#\s])?$/u, {
|
|
4
|
+
message: "Expected an http(s) base URL without a query or a trailing slash",
|
|
5
|
+
})).pipe(Schema.brand("UpstreamBase"));
|
|
6
|
+
//# sourceMappingURL=upstream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upstream.js","sourceRoot":"","sources":["../src/upstream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,8HAA8H;AAC9H,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAC7C,MAAM,CAAC,SAAS,CAAC,gDAAgD,EAAE;IACjE,OAAO,EAAE,kEAAkE;CAC5E,CAAC,CACH,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,61 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usine/gateway",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "The usine gateway: a credential-injecting proxy for GitHub and LLM providers, and an egress allowlist, in front of Worker VMs.",
|
|
5
|
+
"license": "AGPL-3.0-only",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/basaltbytes/usine.git",
|
|
9
|
+
"directory": "packages/gateway"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"usine-gateway": "./dist/node/main.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"!dist/tsconfig.tsbuildinfo"
|
|
17
|
+
],
|
|
18
|
+
"type": "module",
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/gateway.d.ts",
|
|
23
|
+
"default": "./dist/gateway.js"
|
|
24
|
+
},
|
|
25
|
+
"./admin": {
|
|
26
|
+
"types": "./dist/admin/api.d.ts",
|
|
27
|
+
"default": "./dist/admin/api.js"
|
|
28
|
+
},
|
|
29
|
+
"./node": {
|
|
30
|
+
"types": "./dist/node/node.d.ts",
|
|
31
|
+
"default": "./dist/node/node.js"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@effect/platform-node": "4.0.6",
|
|
39
|
+
"@effect/platform-node-shared": "4.0.6",
|
|
40
|
+
"@usine/core": "0.5.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@effect/vitest": "4.0.6",
|
|
44
|
+
"effect": "4.0.6",
|
|
45
|
+
"typescript": "7.0.2",
|
|
46
|
+
"vitest": "5.0.5",
|
|
47
|
+
"@usine/tsconfig": "0.0.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"effect": "4.0.6"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=22"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "tsc -b",
|
|
57
|
+
"check": "tsc -p tsconfig.check.json",
|
|
58
|
+
"test": "vitest run --exclude 'test/placeholder-swap/**'",
|
|
59
|
+
"test:placeholder-swap": "vitest run test/placeholder-swap"
|
|
60
|
+
}
|
|
6
61
|
}
|