@hasna/uptime 0.1.23 → 0.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/Dockerfile.package +2 -2
- package/NOTICE +1 -1
- package/README.md +9 -3
- package/THIRD_PARTY_NOTICES.md +4 -1
- package/bun.lock +221 -0
- package/dist/api.js +111 -33
- package/dist/cli/index.js +169 -43
- package/dist/cloud-plan.d.ts +14 -1
- package/dist/cloud-plan.d.ts.map +1 -1
- package/dist/cloud-plan.js +27 -7
- package/dist/index.js +138 -40
- package/dist/mcp/index.js +111 -33
- package/dist/service.d.ts +19 -0
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +111 -33
- package/docs/aws-deployment-runbook.md +40 -14
- package/docs/aws-runtime-security.md +25 -10
- package/docs/cloud-source-of-truth.md +10 -7
- package/docs/deployment-metadata.example.json +4 -2
- package/infra/aws/README.md +26 -11
- package/infra/aws/main.tf +116 -34
- package/infra/aws/outputs.tf +8 -0
- package/infra/aws/terraform.tfvars.example +4 -1
- package/infra/aws/variables.tf +54 -5
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -3150,12 +3150,18 @@ var MAX_PROBE_RESULT_FUTURE_MS = 5 * 60000;
|
|
|
3150
3150
|
class UptimeService {
|
|
3151
3151
|
store;
|
|
3152
3152
|
checkRunner;
|
|
3153
|
+
hostedResolveHost;
|
|
3154
|
+
hostedHttpRequest;
|
|
3155
|
+
hostedMaxRedirects;
|
|
3153
3156
|
leaseOwner = `svc_${randomUUID3().replace(/-/g, "").slice(0, 18)}`;
|
|
3154
3157
|
inFlightChecks = new Set;
|
|
3155
3158
|
inFlightReportSchedules = new Set;
|
|
3156
3159
|
constructor(options = {}) {
|
|
3157
3160
|
this.store = options.store ?? new UptimeStore({ mode: "local", ...options });
|
|
3158
3161
|
this.checkRunner = options.checkRunner ?? runMonitorCheck;
|
|
3162
|
+
this.hostedResolveHost = options.hostedResolveHost;
|
|
3163
|
+
this.hostedHttpRequest = options.hostedHttpRequest;
|
|
3164
|
+
this.hostedMaxRedirects = options.hostedMaxRedirects;
|
|
3159
3165
|
}
|
|
3160
3166
|
close() {
|
|
3161
3167
|
this.store.close();
|
|
@@ -3362,39 +3368,7 @@ class UptimeService {
|
|
|
3362
3368
|
const monitor = this.store.getMonitor(idOrName);
|
|
3363
3369
|
if (!monitor)
|
|
3364
3370
|
throw new Error(`Monitor not found: ${idOrName}`);
|
|
3365
|
-
|
|
3366
|
-
throw new Error(`Monitor is disabled: ${monitor.name}`);
|
|
3367
|
-
if (this.inFlightChecks.has(monitor.id))
|
|
3368
|
-
throw new Error(`Monitor check already in progress: ${monitor.name}`);
|
|
3369
|
-
const leaseTtlMs = Math.max(60000, (monitor.retryCount + 1) * monitor.timeoutMs + 1e4);
|
|
3370
|
-
if (!this.store.acquireCheckLease(monitor.id, this.leaseOwner, leaseTtlMs)) {
|
|
3371
|
-
throw new MonitorCheckBusyError(`Monitor check already in progress: ${monitor.name}`);
|
|
3372
|
-
}
|
|
3373
|
-
this.inFlightChecks.add(monitor.id);
|
|
3374
|
-
try {
|
|
3375
|
-
let attemptCount = 0;
|
|
3376
|
-
let last = null;
|
|
3377
|
-
const maxAttempts = Math.max(1, monitor.retryCount + 1);
|
|
3378
|
-
while (attemptCount < maxAttempts) {
|
|
3379
|
-
attemptCount += 1;
|
|
3380
|
-
last = await this.checkRunner(monitor);
|
|
3381
|
-
if (last.status === "up")
|
|
3382
|
-
break;
|
|
3383
|
-
}
|
|
3384
|
-
return this.store.recordCheckResult({
|
|
3385
|
-
monitorId: monitor.id,
|
|
3386
|
-
status: last.status,
|
|
3387
|
-
latencyMs: last.latencyMs,
|
|
3388
|
-
statusCode: last.statusCode ?? null,
|
|
3389
|
-
error: last.error ?? null,
|
|
3390
|
-
evidence: last.evidence ?? null,
|
|
3391
|
-
attemptCount,
|
|
3392
|
-
expectedMonitorRevision: monitor.revision
|
|
3393
|
-
});
|
|
3394
|
-
} finally {
|
|
3395
|
-
this.inFlightChecks.delete(monitor.id);
|
|
3396
|
-
this.store.releaseCheckLease(monitor.id, this.leaseOwner);
|
|
3397
|
-
}
|
|
3371
|
+
return this.recordMonitorCheck(monitor, { hostedTargetPolicy: false });
|
|
3398
3372
|
}
|
|
3399
3373
|
async checkAll() {
|
|
3400
3374
|
if (this.store.mode === "hosted")
|
|
@@ -3406,6 +3380,49 @@ class UptimeService {
|
|
|
3406
3380
|
}
|
|
3407
3381
|
return results;
|
|
3408
3382
|
}
|
|
3383
|
+
async checkHostedPublicMonitor(idOrName, options = {}) {
|
|
3384
|
+
this.assertHostedPublicChecksEnabled();
|
|
3385
|
+
const workspaceId = this.requireHostedWorkerWorkspaceId(options.workspaceId);
|
|
3386
|
+
const monitor = this.store.getMonitor(idOrName, { workspaceId });
|
|
3387
|
+
if (!monitor)
|
|
3388
|
+
throw new Error(`Monitor not found: ${idOrName}`);
|
|
3389
|
+
this.assertHostedPublicMonitor(monitor);
|
|
3390
|
+
const result = await this.recordMonitorCheck(monitor, { hostedTargetPolicy: true });
|
|
3391
|
+
this.auditStore().recordAuditEvent({
|
|
3392
|
+
workspaceId,
|
|
3393
|
+
action: "hosted_public_check.run",
|
|
3394
|
+
resourceType: "monitor",
|
|
3395
|
+
resourceId: monitor.id,
|
|
3396
|
+
message: `Ran hosted public check for ${monitor.name}`,
|
|
3397
|
+
metadata: {
|
|
3398
|
+
checkResultId: result.id,
|
|
3399
|
+
status: result.status,
|
|
3400
|
+
monitorKind: monitor.kind,
|
|
3401
|
+
operatorPath: "hosted_public_check"
|
|
3402
|
+
},
|
|
3403
|
+
actor: "hosted-public-check-worker"
|
|
3404
|
+
});
|
|
3405
|
+
return result;
|
|
3406
|
+
}
|
|
3407
|
+
async runDueHostedPublicChecks(now = new Date, options = {}) {
|
|
3408
|
+
this.assertHostedPublicChecksEnabled();
|
|
3409
|
+
const workspaceId = this.requireHostedWorkerWorkspaceId(options.workspaceId);
|
|
3410
|
+
const due = this.store.listMonitors({ workspaceId }).filter((monitor) => this.isHostedPublicMonitor(monitor) && this.isDue(monitor, now));
|
|
3411
|
+
const results = [];
|
|
3412
|
+
for (const monitor of due) {
|
|
3413
|
+
const current = this.store.getMonitor(monitor.id, { workspaceId });
|
|
3414
|
+
if (!current || !this.isHostedPublicMonitor(current) || !this.isDue(current, now))
|
|
3415
|
+
continue;
|
|
3416
|
+
try {
|
|
3417
|
+
results.push(await this.checkHostedPublicMonitor(current.id, { workspaceId }));
|
|
3418
|
+
} catch (error) {
|
|
3419
|
+
if (error instanceof MonitorCheckBusyError || error instanceof StaleCheckResultError)
|
|
3420
|
+
continue;
|
|
3421
|
+
throw error;
|
|
3422
|
+
}
|
|
3423
|
+
}
|
|
3424
|
+
return results;
|
|
3425
|
+
}
|
|
3409
3426
|
startScheduler(options = {}) {
|
|
3410
3427
|
if (this.store.mode === "hosted")
|
|
3411
3428
|
throw new Error("hosted scheduler requires check_jobs and probes");
|
|
@@ -3451,6 +3468,67 @@ class UptimeService {
|
|
|
3451
3468
|
const last = new Date(monitor.lastCheckedAt).getTime();
|
|
3452
3469
|
return now.getTime() - last >= monitor.intervalSeconds * 1000;
|
|
3453
3470
|
}
|
|
3471
|
+
async recordMonitorCheck(monitor, options) {
|
|
3472
|
+
if (!monitor.enabled)
|
|
3473
|
+
throw new Error(`Monitor is disabled: ${monitor.name}`);
|
|
3474
|
+
if (this.inFlightChecks.has(monitor.id))
|
|
3475
|
+
throw new Error(`Monitor check already in progress: ${monitor.name}`);
|
|
3476
|
+
const leaseTtlMs = Math.max(60000, (monitor.retryCount + 1) * monitor.timeoutMs + 1e4);
|
|
3477
|
+
if (!this.store.acquireCheckLease(monitor.id, this.leaseOwner, leaseTtlMs)) {
|
|
3478
|
+
throw new MonitorCheckBusyError(`Monitor check already in progress: ${monitor.name}`);
|
|
3479
|
+
}
|
|
3480
|
+
this.inFlightChecks.add(monitor.id);
|
|
3481
|
+
try {
|
|
3482
|
+
let attemptCount = 0;
|
|
3483
|
+
let last = null;
|
|
3484
|
+
const maxAttempts = Math.max(1, monitor.retryCount + 1);
|
|
3485
|
+
while (attemptCount < maxAttempts) {
|
|
3486
|
+
attemptCount += 1;
|
|
3487
|
+
last = options.hostedTargetPolicy ? await this.runHostedPublicCheckAttempt(monitor) : await this.checkRunner(monitor);
|
|
3488
|
+
if (last.status === "up")
|
|
3489
|
+
break;
|
|
3490
|
+
}
|
|
3491
|
+
return this.store.recordCheckResult({
|
|
3492
|
+
monitorId: monitor.id,
|
|
3493
|
+
status: last.status,
|
|
3494
|
+
latencyMs: last.latencyMs,
|
|
3495
|
+
statusCode: last.statusCode ?? null,
|
|
3496
|
+
error: last.error ?? null,
|
|
3497
|
+
evidence: last.evidence ?? null,
|
|
3498
|
+
attemptCount,
|
|
3499
|
+
expectedMonitorRevision: monitor.revision
|
|
3500
|
+
});
|
|
3501
|
+
} finally {
|
|
3502
|
+
this.inFlightChecks.delete(monitor.id);
|
|
3503
|
+
this.store.releaseCheckLease(monitor.id, this.leaseOwner);
|
|
3504
|
+
}
|
|
3505
|
+
}
|
|
3506
|
+
runHostedPublicCheckAttempt(monitor) {
|
|
3507
|
+
return runMonitorCheck(monitor, {
|
|
3508
|
+
hostedTargetPolicy: true,
|
|
3509
|
+
resolveHost: this.hostedResolveHost,
|
|
3510
|
+
hostedHttpRequest: this.hostedHttpRequest,
|
|
3511
|
+
maxRedirects: this.hostedMaxRedirects
|
|
3512
|
+
});
|
|
3513
|
+
}
|
|
3514
|
+
assertHostedPublicChecksEnabled() {
|
|
3515
|
+
if (this.store.mode !== "hosted")
|
|
3516
|
+
throw new Error("hosted public checks require hosted mode");
|
|
3517
|
+
}
|
|
3518
|
+
requireHostedWorkerWorkspaceId(workspaceId) {
|
|
3519
|
+
const value = workspaceId?.trim() || process.env.HASNA_UPTIME_WORKSPACE_ID?.trim();
|
|
3520
|
+
if (!value)
|
|
3521
|
+
throw new Error("hosted public checks require a workspace id");
|
|
3522
|
+
return value;
|
|
3523
|
+
}
|
|
3524
|
+
assertHostedPublicMonitor(monitor) {
|
|
3525
|
+
if (!this.isHostedPublicMonitor(monitor)) {
|
|
3526
|
+
throw new Error("hosted public checks support only HTTP and TCP monitors");
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3529
|
+
isHostedPublicMonitor(monitor) {
|
|
3530
|
+
return monitor.kind === "http" || monitor.kind === "tcp";
|
|
3531
|
+
}
|
|
3454
3532
|
probeStore() {
|
|
3455
3533
|
if (this.store.mode === "hosted") {
|
|
3456
3534
|
throw new Error("hosted probe APIs require cloud check_jobs, workspace stores, and audit logging");
|
|
@@ -4545,6 +4623,7 @@ var DEFAULT_WORKSPACE_ID = "workspace-id";
|
|
|
4545
4623
|
var DEFAULT_VPC_ID = "vpc-xxxxxxxx";
|
|
4546
4624
|
var DEFAULT_HOSTED_SQLITE_DB = "/data/uptime/uptime.db";
|
|
4547
4625
|
var DEFAULT_PROTECTED_ACCESS_MODE = "cloudfront_default_domain";
|
|
4626
|
+
var DEFAULT_CLOUDFRONT_ORIGIN_PROTOCOL_POLICY = "http-only";
|
|
4548
4627
|
function buildAwsDeploymentPlan(options = {}) {
|
|
4549
4628
|
const region = clean(options.region, DEFAULT_REGION);
|
|
4550
4629
|
const stage = clean(options.stage, DEFAULT_STAGE);
|
|
@@ -4557,8 +4636,11 @@ function buildAwsDeploymentPlan(options = {}) {
|
|
|
4557
4636
|
const image = clean(options.image, `${imageRepositoryUri}@sha256:<image-digest>`);
|
|
4558
4637
|
const evidenceBucket = clean(options.evidenceBucket, `hasna-${stage}-${prefix}-evidence`);
|
|
4559
4638
|
const hostedSqliteDbPath = clean(options.hostedSqliteDbPath, DEFAULT_HOSTED_SQLITE_DB);
|
|
4560
|
-
const runtimePackageVersion = clean(options.runtimePackageVersion, "0.1.
|
|
4639
|
+
const runtimePackageVersion = clean(options.runtimePackageVersion, "0.1.25");
|
|
4640
|
+
const runtimePackageIntegrity = options.runtimePackageIntegrity?.trim() || undefined;
|
|
4561
4641
|
const protectedAccessMode = options.protectedAccessMode ?? DEFAULT_PROTECTED_ACCESS_MODE;
|
|
4642
|
+
const cloudfrontOriginProtocolPolicy = options.cloudfrontOriginProtocolPolicy ?? DEFAULT_CLOUDFRONT_ORIGIN_PROTOCOL_POLICY;
|
|
4643
|
+
const cloudfrontOriginDomainName = clean(options.cloudfrontOriginDomainName, "<alb-dns-name>");
|
|
4562
4644
|
const protectedAccessUrl = protectedAccessMode === "cloudfront_default_domain" ? "https://<cloudfront-domain>" : `https://${hostname}`;
|
|
4563
4645
|
const cluster = `${prefix}-${stage}`;
|
|
4564
4646
|
const secrets = {
|
|
@@ -4625,6 +4707,13 @@ function buildAwsDeploymentPlan(options = {}) {
|
|
|
4625
4707
|
protectedAccessMode,
|
|
4626
4708
|
edgeDistribution: protectedAccessMode === "cloudfront_default_domain" ? `${prefix}-${stage}-edge` : undefined,
|
|
4627
4709
|
protectedAccessUrl,
|
|
4710
|
+
cloudfrontOrigin: protectedAccessMode === "cloudfront_default_domain" ? {
|
|
4711
|
+
protocolPolicy: cloudfrontOriginProtocolPolicy,
|
|
4712
|
+
domainName: cloudfrontOriginProtocolPolicy === "https-only" ? cloudfrontOriginDomainName : "<alb-dns-name>",
|
|
4713
|
+
requiresMatchingCertificate: cloudfrontOriginProtocolPolicy === "https-only",
|
|
4714
|
+
liveTrafficApproved: false,
|
|
4715
|
+
risk: cloudfrontOriginProtocolPolicy === "http-only" ? "Temporary HTTP-origin bridge: do not use for token-bearing live traffic without explicit risk acceptance, or switch to https-only with cloudfront_origin_domain_name plus certificate_arn." : "CloudFront HTTPS-origin mode requires the origin hostname to resolve to the ALB and match certificate_arn."
|
|
4716
|
+
} : undefined,
|
|
4628
4717
|
originVerification: protectedAccessMode === "cloudfront_default_domain" ? {
|
|
4629
4718
|
mode: "cloudfront_origin_header",
|
|
4630
4719
|
requiredBeforeScaleUp: true,
|
|
@@ -4657,6 +4746,7 @@ function buildAwsDeploymentPlan(options = {}) {
|
|
|
4657
4746
|
repository: ecrRepository,
|
|
4658
4747
|
uri: image,
|
|
4659
4748
|
dockerfile: "Dockerfile.package",
|
|
4749
|
+
expectedIntegrity: runtimePackageIntegrity,
|
|
4660
4750
|
buildCommand: `BLOCKED: after infra approval, AWS CodeBuild builds Dockerfile.package from @hasna/uptime@${runtimePackageVersion} into ${imageRepositoryUri}`,
|
|
4661
4751
|
pushCommands: [
|
|
4662
4752
|
`BLOCKED: start ${prefix}-${stage}-image-builder only through the approved deploy pipeline after @hasna/uptime@${runtimePackageVersion} is published`,
|
|
@@ -4683,16 +4773,16 @@ function buildAwsDeploymentPlan(options = {}) {
|
|
|
4683
4773
|
`Infra PR must declare CodeBuild image builder ${prefix}-${stage}-image-builder for @hasna/uptime@${runtimePackageVersion}.`,
|
|
4684
4774
|
`Infra PR must declare hardened S3 evidence bucket ${evidenceBucket} with KMS, versioning, lifecycle, and public access block.`,
|
|
4685
4775
|
`Infra PR must declare encrypted EFS ${prefix}-${stage}-data with access point, mount targets, and AWS Backup plan.`,
|
|
4686
|
-
protectedAccessMode === "cloudfront_default_domain" ? "Infra PR must declare CloudFront default-domain HTTPS edge, ALB
|
|
4776
|
+
protectedAccessMode === "cloudfront_default_domain" ? "Infra PR must declare CloudFront default-domain HTTPS edge, ALB origin listener restricted to CloudFront origin-facing ranges, CloudFront-only origin verification header binding, ECS/Fargate cluster, target groups, security groups, IAM roles, CloudWatch log groups, and Secrets Manager refs. Token-bearing live traffic must use cloudfront_origin_protocol_policy=https-only with a matching origin hostname/certificate, or carry explicit HTTP-origin risk acceptance." : `Infra PR must declare ECS/Fargate cluster ${cluster}, ALB HTTPS listener, target groups, security groups, IAM roles, CloudWatch log groups, and Secrets Manager refs.`,
|
|
4687
4777
|
"Only apply the infra plan from the approved infrastructure repository after review evidence is attached."
|
|
4688
4778
|
],
|
|
4689
4779
|
deploy: [
|
|
4690
4780
|
"Build and publish the image only after the Dockerfile/container target is reviewed.",
|
|
4691
|
-
`Start the AWS image builder for @hasna/uptime@${runtimePackageVersion}
|
|
4781
|
+
runtimePackageIntegrity ? `Start the AWS image builder for @hasna/uptime@${runtimePackageVersion}; it must verify npm dist.integrity ${runtimePackageIntegrity} before extracting the package, then record the pushed image digest.` : `Start the AWS image builder for @hasna/uptime@${runtimePackageVersion}; set runtime_package_integrity from npm dist.integrity before live use, then record the pushed image digest.`,
|
|
4692
4782
|
"For the EFS SQLite bridge, do not run migration, scheduler, public-probe, or reporter tasks; keep them at desired count 0 until Postgres and cloud leases exist.",
|
|
4693
4783
|
`Register task definitions for ${services.map((service) => service.name).join(", ")} using valueFrom secrets.`,
|
|
4694
4784
|
`Update ECS services in cluster ${cluster} one component at a time through the approved deploy pipeline.`,
|
|
4695
|
-
protectedAccessMode === "cloudfront_default_domain" ? "Use the CloudFront default HTTPS domain with origin verification header binding for first protected access;
|
|
4785
|
+
protectedAccessMode === "cloudfront_default_domain" ? "Use the CloudFront default HTTPS domain with origin verification header binding for first protected access; before token-bearing live traffic, switch the origin to https-only with a matching origin hostname/certificate or record explicit HTTP-origin risk acceptance." : `Create Route53/edge record for ${hostname} only after ALB health checks pass and auth denial smokes succeed.`
|
|
4696
4786
|
],
|
|
4697
4787
|
rollback: [
|
|
4698
4788
|
"Keep previous task definition ARNs before each service update.",
|
|
@@ -4709,6 +4799,8 @@ function buildAwsDeploymentPlan(options = {}) {
|
|
|
4709
4799
|
blockers: [
|
|
4710
4800
|
"The infrastructure owner repository was not found in this workspace.",
|
|
4711
4801
|
protectedAccessMode === "cloudfront_default_domain" ? "CloudFront origin verification header binding must be enabled and direct-origin denial must be proven before web desired count is raised above 0." : "ALB HTTPS ingress policy and auth-denial smokes must be proven before web desired count is raised above 0.",
|
|
4802
|
+
...protectedAccessMode === "cloudfront_default_domain" && cloudfrontOriginProtocolPolicy === "http-only" ? ["CloudFront-to-ALB origin transport is still http-only; token-bearing live traffic needs https-only origin mode or explicit risk acceptance."] : [],
|
|
4803
|
+
...protectedAccessMode === "cloudfront_default_domain" && cloudfrontOriginProtocolPolicy === "https-only" && cloudfrontOriginDomainName === "<alb-dns-name>" ? ["CloudFront https-only origin mode needs cloudfront_origin_domain_name that resolves to the ALB and matches certificate_arn."] : [],
|
|
4712
4804
|
"The EFS SQLite bridge is single-writer only: web target desired count is 1 and scheduler/public-probe/reporter targets remain 0 until Postgres and cloud leases exist.",
|
|
4713
4805
|
"Hosted production auth/RBAC must replace broad static hosted-token operation before exposure.",
|
|
4714
4806
|
"Public probe execution still needs cloud check-job leases wired to runHostedHttpCheck and live policy-decision log evidence.",
|
|
@@ -4717,8 +4809,9 @@ function buildAwsDeploymentPlan(options = {}) {
|
|
|
4717
4809
|
requiredEvidence: [
|
|
4718
4810
|
"Infrastructure PR/synth/plan from the approved infra repository.",
|
|
4719
4811
|
"CodeBuild image-builder run, container smoke, and immutable image digest.",
|
|
4812
|
+
"Published package dist.integrity pinned in the private infra root or an explicit not-live exception.",
|
|
4720
4813
|
"ECS task definitions using secrets.valueFrom only.",
|
|
4721
|
-
"CloudFront-default-domain origin-header config
|
|
4814
|
+
"CloudFront-default-domain origin-header config, origin transport decision, direct-origin denial evidence, auth-denial smokes, and web alarm checks.",
|
|
4722
4815
|
"Single-writer ECS evidence: one web task maximum and no scheduler/public-probe/reporter EFS mounts.",
|
|
4723
4816
|
"EFS encryption, access point, mount-target, AWS Backup, and restore-drill evidence.",
|
|
4724
4817
|
"S3 bucket KMS, versioning, lifecycle, and public-access-block evidence.",
|
|
@@ -4731,11 +4824,13 @@ function buildAwsDeploymentPlan(options = {}) {
|
|
|
4731
4824
|
notes: [
|
|
4732
4825
|
"This plan generator does not call AWS.",
|
|
4733
4826
|
"Blocked plan output intentionally avoids copy-pastable AWS mutation commands.",
|
|
4734
|
-
"Default protected access uses CloudFront's HTTPS default domain so first deploy is not blocked on custom DNS or ACM.",
|
|
4827
|
+
"Default protected access uses CloudFront's HTTPS default domain so first zero-count deploy is not blocked on custom DNS or ACM.",
|
|
4735
4828
|
"CloudFront default-domain mode still requires origin verification header binding before live scale-up; the header value is sensitive state/config material, not public documentation.",
|
|
4829
|
+
"CloudFront HTTPS-origin mode requires a dedicated origin DNS hostname and matching ACM certificate; do not assume the ALB DNS name can satisfy TLS verification.",
|
|
4736
4830
|
"Hosted runtime uses explicit EFS-backed SQLite at HASNA_UPTIME_HOSTED_SQLITE_DB until the async Postgres adapter exists.",
|
|
4737
4831
|
"Do not set HASNA_UPTIME_DATABASE_URL for hosted tasks until the Postgres adapter is implemented.",
|
|
4738
4832
|
"Secrets are represented as secret names/refs and must be injected with valueFrom.",
|
|
4833
|
+
"Set runtime_package_integrity in the approved infra root after publish so the AWS image builder verifies the npm tarball before ECR build.",
|
|
4739
4834
|
"Actual deploy belongs in the deploy_release_operate_final goal node after infra review."
|
|
4740
4835
|
]
|
|
4741
4836
|
}
|
|
@@ -4802,7 +4897,10 @@ function buildPrivateProbeCloudConfig(options = {}) {
|
|
|
4802
4897
|
}
|
|
4803
4898
|
};
|
|
4804
4899
|
}
|
|
4805
|
-
function renderPrivateProbeEnv(config) {
|
|
4900
|
+
function renderPrivateProbeEnv(config, options = {}) {
|
|
4901
|
+
if (!options.allowBlocked && (!config.canStart || config.blockers.length > 0)) {
|
|
4902
|
+
throw new Error("private probe env output is blocked until hosted probe routes and cloud jobs are implemented");
|
|
4903
|
+
}
|
|
4806
4904
|
const required = ["HASNA_UPTIME_PRIVATE_PROBE_ID"];
|
|
4807
4905
|
const missing = required.filter((key) => !config.env[key]);
|
|
4808
4906
|
if (missing.length > 0) {
|
package/dist/mcp/index.js
CHANGED
|
@@ -17438,12 +17438,18 @@ var MAX_PROBE_RESULT_FUTURE_MS = 5 * 60000;
|
|
|
17438
17438
|
class UptimeService {
|
|
17439
17439
|
store;
|
|
17440
17440
|
checkRunner;
|
|
17441
|
+
hostedResolveHost;
|
|
17442
|
+
hostedHttpRequest;
|
|
17443
|
+
hostedMaxRedirects;
|
|
17441
17444
|
leaseOwner = `svc_${randomUUID3().replace(/-/g, "").slice(0, 18)}`;
|
|
17442
17445
|
inFlightChecks = new Set;
|
|
17443
17446
|
inFlightReportSchedules = new Set;
|
|
17444
17447
|
constructor(options = {}) {
|
|
17445
17448
|
this.store = options.store ?? new UptimeStore({ mode: "local", ...options });
|
|
17446
17449
|
this.checkRunner = options.checkRunner ?? runMonitorCheck;
|
|
17450
|
+
this.hostedResolveHost = options.hostedResolveHost;
|
|
17451
|
+
this.hostedHttpRequest = options.hostedHttpRequest;
|
|
17452
|
+
this.hostedMaxRedirects = options.hostedMaxRedirects;
|
|
17447
17453
|
}
|
|
17448
17454
|
close() {
|
|
17449
17455
|
this.store.close();
|
|
@@ -17650,39 +17656,7 @@ class UptimeService {
|
|
|
17650
17656
|
const monitor = this.store.getMonitor(idOrName);
|
|
17651
17657
|
if (!monitor)
|
|
17652
17658
|
throw new Error(`Monitor not found: ${idOrName}`);
|
|
17653
|
-
|
|
17654
|
-
throw new Error(`Monitor is disabled: ${monitor.name}`);
|
|
17655
|
-
if (this.inFlightChecks.has(monitor.id))
|
|
17656
|
-
throw new Error(`Monitor check already in progress: ${monitor.name}`);
|
|
17657
|
-
const leaseTtlMs = Math.max(60000, (monitor.retryCount + 1) * monitor.timeoutMs + 1e4);
|
|
17658
|
-
if (!this.store.acquireCheckLease(monitor.id, this.leaseOwner, leaseTtlMs)) {
|
|
17659
|
-
throw new MonitorCheckBusyError(`Monitor check already in progress: ${monitor.name}`);
|
|
17660
|
-
}
|
|
17661
|
-
this.inFlightChecks.add(monitor.id);
|
|
17662
|
-
try {
|
|
17663
|
-
let attemptCount = 0;
|
|
17664
|
-
let last = null;
|
|
17665
|
-
const maxAttempts = Math.max(1, monitor.retryCount + 1);
|
|
17666
|
-
while (attemptCount < maxAttempts) {
|
|
17667
|
-
attemptCount += 1;
|
|
17668
|
-
last = await this.checkRunner(monitor);
|
|
17669
|
-
if (last.status === "up")
|
|
17670
|
-
break;
|
|
17671
|
-
}
|
|
17672
|
-
return this.store.recordCheckResult({
|
|
17673
|
-
monitorId: monitor.id,
|
|
17674
|
-
status: last.status,
|
|
17675
|
-
latencyMs: last.latencyMs,
|
|
17676
|
-
statusCode: last.statusCode ?? null,
|
|
17677
|
-
error: last.error ?? null,
|
|
17678
|
-
evidence: last.evidence ?? null,
|
|
17679
|
-
attemptCount,
|
|
17680
|
-
expectedMonitorRevision: monitor.revision
|
|
17681
|
-
});
|
|
17682
|
-
} finally {
|
|
17683
|
-
this.inFlightChecks.delete(monitor.id);
|
|
17684
|
-
this.store.releaseCheckLease(monitor.id, this.leaseOwner);
|
|
17685
|
-
}
|
|
17659
|
+
return this.recordMonitorCheck(monitor, { hostedTargetPolicy: false });
|
|
17686
17660
|
}
|
|
17687
17661
|
async checkAll() {
|
|
17688
17662
|
if (this.store.mode === "hosted")
|
|
@@ -17694,6 +17668,49 @@ class UptimeService {
|
|
|
17694
17668
|
}
|
|
17695
17669
|
return results;
|
|
17696
17670
|
}
|
|
17671
|
+
async checkHostedPublicMonitor(idOrName, options = {}) {
|
|
17672
|
+
this.assertHostedPublicChecksEnabled();
|
|
17673
|
+
const workspaceId = this.requireHostedWorkerWorkspaceId(options.workspaceId);
|
|
17674
|
+
const monitor = this.store.getMonitor(idOrName, { workspaceId });
|
|
17675
|
+
if (!monitor)
|
|
17676
|
+
throw new Error(`Monitor not found: ${idOrName}`);
|
|
17677
|
+
this.assertHostedPublicMonitor(monitor);
|
|
17678
|
+
const result = await this.recordMonitorCheck(monitor, { hostedTargetPolicy: true });
|
|
17679
|
+
this.auditStore().recordAuditEvent({
|
|
17680
|
+
workspaceId,
|
|
17681
|
+
action: "hosted_public_check.run",
|
|
17682
|
+
resourceType: "monitor",
|
|
17683
|
+
resourceId: monitor.id,
|
|
17684
|
+
message: `Ran hosted public check for ${monitor.name}`,
|
|
17685
|
+
metadata: {
|
|
17686
|
+
checkResultId: result.id,
|
|
17687
|
+
status: result.status,
|
|
17688
|
+
monitorKind: monitor.kind,
|
|
17689
|
+
operatorPath: "hosted_public_check"
|
|
17690
|
+
},
|
|
17691
|
+
actor: "hosted-public-check-worker"
|
|
17692
|
+
});
|
|
17693
|
+
return result;
|
|
17694
|
+
}
|
|
17695
|
+
async runDueHostedPublicChecks(now = new Date, options = {}) {
|
|
17696
|
+
this.assertHostedPublicChecksEnabled();
|
|
17697
|
+
const workspaceId = this.requireHostedWorkerWorkspaceId(options.workspaceId);
|
|
17698
|
+
const due = this.store.listMonitors({ workspaceId }).filter((monitor) => this.isHostedPublicMonitor(monitor) && this.isDue(monitor, now));
|
|
17699
|
+
const results = [];
|
|
17700
|
+
for (const monitor of due) {
|
|
17701
|
+
const current = this.store.getMonitor(monitor.id, { workspaceId });
|
|
17702
|
+
if (!current || !this.isHostedPublicMonitor(current) || !this.isDue(current, now))
|
|
17703
|
+
continue;
|
|
17704
|
+
try {
|
|
17705
|
+
results.push(await this.checkHostedPublicMonitor(current.id, { workspaceId }));
|
|
17706
|
+
} catch (error51) {
|
|
17707
|
+
if (error51 instanceof MonitorCheckBusyError || error51 instanceof StaleCheckResultError)
|
|
17708
|
+
continue;
|
|
17709
|
+
throw error51;
|
|
17710
|
+
}
|
|
17711
|
+
}
|
|
17712
|
+
return results;
|
|
17713
|
+
}
|
|
17697
17714
|
startScheduler(options = {}) {
|
|
17698
17715
|
if (this.store.mode === "hosted")
|
|
17699
17716
|
throw new Error("hosted scheduler requires check_jobs and probes");
|
|
@@ -17739,6 +17756,67 @@ class UptimeService {
|
|
|
17739
17756
|
const last = new Date(monitor.lastCheckedAt).getTime();
|
|
17740
17757
|
return now.getTime() - last >= monitor.intervalSeconds * 1000;
|
|
17741
17758
|
}
|
|
17759
|
+
async recordMonitorCheck(monitor, options) {
|
|
17760
|
+
if (!monitor.enabled)
|
|
17761
|
+
throw new Error(`Monitor is disabled: ${monitor.name}`);
|
|
17762
|
+
if (this.inFlightChecks.has(monitor.id))
|
|
17763
|
+
throw new Error(`Monitor check already in progress: ${monitor.name}`);
|
|
17764
|
+
const leaseTtlMs = Math.max(60000, (monitor.retryCount + 1) * monitor.timeoutMs + 1e4);
|
|
17765
|
+
if (!this.store.acquireCheckLease(monitor.id, this.leaseOwner, leaseTtlMs)) {
|
|
17766
|
+
throw new MonitorCheckBusyError(`Monitor check already in progress: ${monitor.name}`);
|
|
17767
|
+
}
|
|
17768
|
+
this.inFlightChecks.add(monitor.id);
|
|
17769
|
+
try {
|
|
17770
|
+
let attemptCount = 0;
|
|
17771
|
+
let last = null;
|
|
17772
|
+
const maxAttempts = Math.max(1, monitor.retryCount + 1);
|
|
17773
|
+
while (attemptCount < maxAttempts) {
|
|
17774
|
+
attemptCount += 1;
|
|
17775
|
+
last = options.hostedTargetPolicy ? await this.runHostedPublicCheckAttempt(monitor) : await this.checkRunner(monitor);
|
|
17776
|
+
if (last.status === "up")
|
|
17777
|
+
break;
|
|
17778
|
+
}
|
|
17779
|
+
return this.store.recordCheckResult({
|
|
17780
|
+
monitorId: monitor.id,
|
|
17781
|
+
status: last.status,
|
|
17782
|
+
latencyMs: last.latencyMs,
|
|
17783
|
+
statusCode: last.statusCode ?? null,
|
|
17784
|
+
error: last.error ?? null,
|
|
17785
|
+
evidence: last.evidence ?? null,
|
|
17786
|
+
attemptCount,
|
|
17787
|
+
expectedMonitorRevision: monitor.revision
|
|
17788
|
+
});
|
|
17789
|
+
} finally {
|
|
17790
|
+
this.inFlightChecks.delete(monitor.id);
|
|
17791
|
+
this.store.releaseCheckLease(monitor.id, this.leaseOwner);
|
|
17792
|
+
}
|
|
17793
|
+
}
|
|
17794
|
+
runHostedPublicCheckAttempt(monitor) {
|
|
17795
|
+
return runMonitorCheck(monitor, {
|
|
17796
|
+
hostedTargetPolicy: true,
|
|
17797
|
+
resolveHost: this.hostedResolveHost,
|
|
17798
|
+
hostedHttpRequest: this.hostedHttpRequest,
|
|
17799
|
+
maxRedirects: this.hostedMaxRedirects
|
|
17800
|
+
});
|
|
17801
|
+
}
|
|
17802
|
+
assertHostedPublicChecksEnabled() {
|
|
17803
|
+
if (this.store.mode !== "hosted")
|
|
17804
|
+
throw new Error("hosted public checks require hosted mode");
|
|
17805
|
+
}
|
|
17806
|
+
requireHostedWorkerWorkspaceId(workspaceId) {
|
|
17807
|
+
const value = workspaceId?.trim() || process.env.HASNA_UPTIME_WORKSPACE_ID?.trim();
|
|
17808
|
+
if (!value)
|
|
17809
|
+
throw new Error("hosted public checks require a workspace id");
|
|
17810
|
+
return value;
|
|
17811
|
+
}
|
|
17812
|
+
assertHostedPublicMonitor(monitor) {
|
|
17813
|
+
if (!this.isHostedPublicMonitor(monitor)) {
|
|
17814
|
+
throw new Error("hosted public checks support only HTTP and TCP monitors");
|
|
17815
|
+
}
|
|
17816
|
+
}
|
|
17817
|
+
isHostedPublicMonitor(monitor) {
|
|
17818
|
+
return monitor.kind === "http" || monitor.kind === "tcp";
|
|
17819
|
+
}
|
|
17742
17820
|
probeStore() {
|
|
17743
17821
|
if (this.store.mode === "hosted") {
|
|
17744
17822
|
throw new Error("hosted probe APIs require cloud check_jobs, workspace stores, and audit logging");
|
package/dist/service.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type HostedDnsResolver, type HostedHttpRequestLike } from "./checks.js";
|
|
1
2
|
import { type ImportApplyResult, type ImportPreview, type ImportRequest, type ImportRollbackResult } from "./imports.js";
|
|
2
3
|
import { type MonitorProvenance, type SaveImportBatchInput, type StoredImportBatch, type UpsertMonitorProvenanceInput, type UptimeBackup, type UptimeBackupCheck, type UptimeStoreOptions } from "./store.js";
|
|
3
4
|
import { type BuildUptimeReportOptions, type SendUptimeReportOptions, type UptimeReport, type UptimeReportDelivery } from "./report.js";
|
|
@@ -5,6 +6,9 @@ import type { AuditEvent, CheckAttemptResult, CheckResult, CreateReportScheduleI
|
|
|
5
6
|
export interface UptimeServiceOptions extends UptimeStoreOptions {
|
|
6
7
|
store?: UptimeStoreLike;
|
|
7
8
|
checkRunner?: (monitor: Monitor) => Promise<CheckAttemptResult>;
|
|
9
|
+
hostedResolveHost?: HostedDnsResolver;
|
|
10
|
+
hostedHttpRequest?: HostedHttpRequestLike;
|
|
11
|
+
hostedMaxRedirects?: number;
|
|
8
12
|
}
|
|
9
13
|
export interface UptimeStoreLike {
|
|
10
14
|
readonly dbPath: string;
|
|
@@ -117,6 +121,9 @@ export interface UptimeStoreLike {
|
|
|
117
121
|
export declare class UptimeService {
|
|
118
122
|
readonly store: UptimeStoreLike;
|
|
119
123
|
private readonly checkRunner;
|
|
124
|
+
private readonly hostedResolveHost?;
|
|
125
|
+
private readonly hostedHttpRequest?;
|
|
126
|
+
private readonly hostedMaxRedirects?;
|
|
120
127
|
private readonly leaseOwner;
|
|
121
128
|
private readonly inFlightChecks;
|
|
122
129
|
private readonly inFlightReportSchedules;
|
|
@@ -201,12 +208,24 @@ export declare class UptimeService {
|
|
|
201
208
|
}): Promise<ReportRun[]>;
|
|
202
209
|
checkMonitor(idOrName: string): Promise<CheckResult>;
|
|
203
210
|
checkAll(): Promise<CheckResult[]>;
|
|
211
|
+
checkHostedPublicMonitor(idOrName: string, options?: {
|
|
212
|
+
workspaceId?: string;
|
|
213
|
+
}): Promise<CheckResult>;
|
|
214
|
+
runDueHostedPublicChecks(now?: Date, options?: {
|
|
215
|
+
workspaceId?: string;
|
|
216
|
+
}): Promise<CheckResult[]>;
|
|
204
217
|
startScheduler(options?: {
|
|
205
218
|
tickMs?: number;
|
|
206
219
|
reportFetchImpl?: typeof fetch;
|
|
207
220
|
}): SchedulerHandle;
|
|
208
221
|
runDueChecks(now?: Date): Promise<CheckResult[]>;
|
|
209
222
|
private isDue;
|
|
223
|
+
private recordMonitorCheck;
|
|
224
|
+
private runHostedPublicCheckAttempt;
|
|
225
|
+
private assertHostedPublicChecksEnabled;
|
|
226
|
+
private requireHostedWorkerWorkspaceId;
|
|
227
|
+
private assertHostedPublicMonitor;
|
|
228
|
+
private isHostedPublicMonitor;
|
|
210
229
|
private probeStore;
|
|
211
230
|
private reportStore;
|
|
212
231
|
private auditStore;
|
package/dist/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|