t3-code-android-nightly/.repos/alchemy-effect/packages/alchemy/test/AWS/Signer/handler.ts
Julius Marminge 6f9cea00ae
chore(refs): sync Effect and Alchemy references to 4.0.1 and beta.80 (#16170)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-05 13:22:30 -07:00

320 lines
12 KiB
TypeScript

import { isBindingHost } from "@/AWS/Lambda/Function.ts";
import * as Lambda from "@/AWS/Lambda";
import * as S3 from "@/AWS/S3";
import * as Signer from "@/AWS/Signer";
import * as Binding from "@/Binding";
import * as Duration from "effect/Duration";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import * as Stream from "effect/Stream";
import { HttpServerRequest } from "effect/http/HttpServerRequest";
import * as HttpServerResponse from "effect/http/HttpServerResponse";
import path from "pathe";
const main = path.resolve(import.meta.dirname, "handler.ts");
/**
* A deterministic one-file zip (`index.js` with a no-op handler) — the code
* artifact the AWSLambda platform signs. Generated once and checked in.
*/
const CODE_ZIP_BASE64 =
"UEsDBBQAAAAAAAAAIVyGZ4n3JAAAACQAAAAIAAAAaW5kZXguanNleHBvcnRzLmhhbmRsZXIgPSBhc3luYyAoKSA9PiAoe30pOwpQSwECFAMUAAAAAAAAACFchmeJ9yQAAAAkAAAACAAAAAAAAAAAAAAAgAEAAAAAaW5kZXguanNQSwUGAAAAAAEAAQA2AAAASgAAAAAA";
const CODE_ZIP = Uint8Array.from(Buffer.from(CODE_ZIP_BASE64, "base64"));
/** A syntactically valid Notary payload for `SignPayload`. */
const NOTARY_PAYLOAD = new TextEncoder().encode(
JSON.stringify({
targetArtifact: {
mediaType: "application/vnd.oci.image.manifest.v1+json",
digest:
"sha256:73c803930ea3ba1e54bc25c2bdc53edd0284c62ed651fe7b00369da519a3c333",
size: 1024,
},
}),
);
const SOURCE_KEY = "code.zip";
export class SignerTestFunction extends Lambda.Function<Lambda.Function>()(
"SignerTestFunction",
) {}
export default SignerTestFunction.make(
{
main,
functionUrl: true,
timeout: Duration.seconds(60),
// The default 128 MB pins at the ceiling (~123 MB used) once the S3 +
// Signer clients are warm and 500s under load — give it headroom.
memorySize: 512,
},
Effect.gen(function* () {
// The profile under test: AWS-managed Lambda code-signing material.
const profile = yield* Signer.SigningProfile("BindingsProfile", {
platformId: "AWSLambda-SHA384-ECDSA",
});
// A Notation profile for the synchronous SignPayload path.
const notationProfile = yield* Signer.SigningProfile("NotationProfile", {
platformId: "Notation-OCI-SHA384-ECDSA",
});
// StartSigningJob reads the versioned source object and writes the
// signed artifact with the CALLER's credentials — bind the S3 access.
const src = yield* S3.Bucket("SignerSrc", {
versioning: "Enabled",
forceDestroy: true,
});
const dst = yield* S3.Bucket("SignerDst", { forceDestroy: true });
// Outputs yield a DEFERRED effect — resolve again per invocation below.
const SrcName = yield* src.bucketName;
const DstName = yield* dst.bucketName;
// Event source: subscribe the host to signing-job status changes. The
// deploy proves the EventBridge rule + invoke permission wiring.
yield* Signer.consumeSigningJobEvents({}, (events) =>
Stream.runForEach(events, (event) =>
Effect.log(`signer job ${event.detail.job_id}: ${event.detail.status}`),
),
);
const putObject = yield* S3.PutObject(src);
yield* S3.GetObject(src); // grants s3:GetObject(Version) for the signing job
yield* S3.PutObject(dst); // grants s3:PutObject on the destination
// Signer validates BUCKET-level access on both buckets when starting a
// job ("S3 bucket … not accessible") — grant the documented signing-
// caller set the object-level bindings above don't cover.
if (!globalThis.__ALCHEMY_RUNTIME__) {
const host = yield* Binding.Host;
if (isBindingHost(host)) {
yield* host.bind`Allow(${host}, SignerSourceDestinationBucketAccess)`({
policyStatements: [
{
Effect: "Allow",
Action: [
"s3:GetBucketLocation",
"s3:GetBucketVersioning",
"s3:ListBucket",
"s3:ListBucketVersions",
],
Resource: [src.bucketArn, dst.bucketArn],
},
],
});
}
}
const startSigningJob = yield* Signer.StartSigningJob(profile);
const signPayload = yield* Signer.SignPayload(notationProfile);
const revokeSigningProfile =
yield* Signer.RevokeSigningProfile(notationProfile);
const describeSigningJob = yield* Signer.DescribeSigningJob();
const listSigningJobs = yield* Signer.ListSigningJobs();
const revokeSignature = yield* Signer.RevokeSignature();
const getRevocationStatus = yield* Signer.GetRevocationStatus();
const getSigningPlatform = yield* Signer.GetSigningPlatform();
const listSigningPlatforms = yield* Signer.ListSigningPlatforms();
const bound = {
startSigningJob,
signPayload,
revokeSigningProfile,
describeSigningJob,
listSigningJobs,
revokeSignature,
getRevocationStatus,
getSigningPlatform,
listSigningPlatforms,
};
return {
fetch: Effect.gen(function* () {
const request = yield* HttpServerRequest;
const url = new URL(request.originalUrl);
const pathname = url.pathname;
const id = url.searchParams.get("id");
if (request.method === "GET" && pathname === "/bindings") {
return yield* HttpServerResponse.json({
bound: Object.keys(bound),
});
}
if (request.method === "GET" && pathname === "/platforms") {
// The catalog paginates with a small page size — walk it (bounded).
const ids: (string | undefined)[] = [];
let nextToken: string | undefined;
let pages = 0;
do {
const page = yield* listSigningPlatforms({
maxResults: 25,
nextToken,
});
ids.push(...(page.platforms ?? []).map((p) => p.platformId));
nextToken = page.nextToken;
pages += 1;
} while (nextToken !== undefined && pages < 10);
return yield* HttpServerResponse.json({ ids });
}
if (request.method === "GET" && pathname === "/platform") {
const platform = yield* getSigningPlatform({
platformId: id ?? "AWSLambda-SHA384-ECDSA",
});
return yield* HttpServerResponse.json({
platformId: platform.platformId,
revocationSupported: platform.revocationSupported ?? false,
});
}
// Upload the code zip (capturing the object version) and start a
// signing job over it — the profileName is injected by the binding.
if (request.method === "POST" && pathname === "/start") {
const uploaded = yield* putObject({
Key: SOURCE_KEY,
Body: CODE_ZIP,
ContentType: "application/zip",
});
if (uploaded.VersionId === undefined) {
// Bucket versioning still propagating — the test re-polls.
return yield* HttpServerResponse.json({
ok: false,
tag: "NoVersionId",
});
}
const started = yield* startSigningJob({
// Required idempotency token — a fresh UUID per request so each
// POST /start begins a new signing job.
clientRequestToken: yield* Effect.sync(() => crypto.randomUUID()),
source: {
s3: {
bucketName: yield* SrcName,
key: SOURCE_KEY,
version: uploaded.VersionId!,
},
},
destination: {
s3: { bucketName: yield* DstName, prefix: "signed/" },
},
}).pipe(Effect.result);
return yield* HttpServerResponse.json(
started._tag === "Success"
? { ok: true, jobId: started.success.jobId }
: {
ok: false,
tag: started.failure._tag,
message: started.failure.message,
},
);
}
if (request.method === "GET" && pathname === "/jobs") {
const { jobs } = yield* listSigningJobs({ maxResults: 25 });
return yield* HttpServerResponse.json({
jobIds: (jobs ?? []).map((j) => j.jobId),
});
}
// Synchronous Notation signing — reports the typed rejection tag if
// Signer refuses the payload so the test can assert the round-trip.
if (request.method === "POST" && pathname === "/sign") {
const signed = yield* signPayload({
payload: NOTARY_PAYLOAD,
payloadFormat: "application/vnd.cncf.notary.payload.v1+json",
}).pipe(Effect.result);
return yield* HttpServerResponse.json(
signed._tag === "Success"
? {
ok: true,
jobId: signed.success.jobId,
hasSignature: (signed.success.signature?.length ?? 0) > 0,
}
: { ok: false, tag: signed.failure._tag },
);
}
if (id === null) {
return yield* HttpServerResponse.json(
{ error: "missing id" },
{ status: 400 },
);
}
if (request.method === "GET" && pathname === "/job") {
// A freshly-started job can 404 for a few seconds (eventual
// consistency) — report the typed tag so the test keeps polling.
const job = yield* describeSigningJob({ jobId: id }).pipe(
Effect.result,
);
return yield* HttpServerResponse.json(
job._tag === "Success"
? {
status: job.success.status,
signedKey: job.success.signedObject?.s3?.key,
}
: { status: "Pending", tag: job.failure._tag },
);
}
if (request.method === "POST" && pathname === "/revoke-job") {
const revoked = yield* revokeSignature({
jobId: id,
reason: "alchemy-test",
}).pipe(Effect.result);
return yield* HttpServerResponse.json(
revoked._tag === "Success"
? { revoked: true }
: { revoked: false, tag: revoked.failure._tag },
);
}
// Revocation-status check for a completed job. ARNs are derived from
// the job's own metadata; empty certificateHashes may be rejected
// with a typed ValidationException — the route reports the tag so
// the test can assert the binding round-trips with IAM intact.
if (request.method === "GET" && pathname === "/revocation") {
const job = yield* describeSigningJob({ jobId: id });
const region = yield* Effect.sync(() => process.env.AWS_REGION);
const arnBase = `arn:aws:signer:${region}:${job.jobOwner}`;
const checked = yield* getRevocationStatus({
signatureTimestamp: job.completedAt ?? new Date(),
platformId: job.platformId!,
profileVersionArn: `${arnBase}:/signing-profiles/${job.profileName}/${job.profileVersion}`,
jobArn: `${arnBase}:/signing-jobs/${job.jobId}`,
certificateHashes: [],
}).pipe(Effect.result);
return yield* HttpServerResponse.json(
checked._tag === "Success"
? {
ok: true,
revokedEntities: checked.success.revokedEntities ?? [],
}
: { ok: false, tag: checked.failure._tag },
);
}
return yield* HttpServerResponse.json(
{ error: "Not found", method: request.method, pathname },
{ status: 404 },
);
}).pipe(Effect.orDie),
};
}).pipe(
Effect.provide(
Layer.mergeAll(
Lambda.EventSource,
S3.PutObjectHttp,
S3.GetObjectHttp,
Signer.StartSigningJobHttp,
Signer.SignPayloadHttp,
Signer.RevokeSigningProfileHttp,
Signer.DescribeSigningJobHttp,
Signer.ListSigningJobsHttp,
Signer.RevokeSignatureHttp,
Signer.GetRevocationStatusHttp,
Signer.GetSigningPlatformHttp,
Signer.ListSigningPlatformsHttp,
),
),
),
);