@hasna/uptime 0.1.23 → 0.1.24
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 +10 -0
- package/NOTICE +1 -1
- package/README.md +4 -1
- package/THIRD_PARTY_NOTICES.md +4 -1
- package/dist/api.js +111 -33
- package/dist/cli/index.js +141 -37
- package/dist/cloud-plan.d.ts +3 -1
- package/dist/cloud-plan.d.ts.map +1 -1
- package/dist/cloud-plan.js +5 -2
- package/dist/index.js +116 -35
- 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 +13 -8
- package/docs/cloud-source-of-truth.md +10 -7
- package/docs/deployment-metadata.example.json +1 -1
- package/infra/aws/terraform.tfvars.example +1 -1
- package/infra/aws/variables.tf +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,16 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.1.24] - 2026-06-29
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Added a workspace-scoped `cloud public-checks run-due` CLI path and SDK
|
|
14
|
+
service methods for bounded hosted HTTP/TCP check execution with hosted target
|
|
15
|
+
policy enforcement. This is a one-off smoke/runtime primitive; the EFS SQLite
|
|
16
|
+
bridge still keeps scheduler, public-probe, reporter, and migration services
|
|
17
|
+
scaled to zero until cloud leases and worker loops are implemented.
|
|
18
|
+
|
|
9
19
|
## [0.1.23] - 2026-06-28
|
|
10
20
|
|
|
11
21
|
### Fixed
|
package/NOTICE
CHANGED
package/README.md
CHANGED
|
@@ -32,7 +32,8 @@ uptime report-schedules run-due
|
|
|
32
32
|
uptime report-schedules runs
|
|
33
33
|
uptime audit
|
|
34
34
|
uptime cloud plan --json
|
|
35
|
-
uptime cloud private-probe-config --probe-id prb_private_01 --machine-id private-probe-01 --
|
|
35
|
+
uptime cloud private-probe-config --probe-id prb_private_01 --machine-id private-probe-01 --json
|
|
36
|
+
uptime cloud private-probe-config --probe-id prb_private_01 --machine-id private-probe-01 --env --allow-blocked-env
|
|
36
37
|
uptime incidents
|
|
37
38
|
uptime serve --port 3899 --check
|
|
38
39
|
```
|
|
@@ -40,6 +41,8 @@ uptime serve --port 3899 --check
|
|
|
40
41
|
Scheduled reports persist endpoint and recipient configuration, but not send
|
|
41
42
|
keys or API tokens. Configure `MAILERY_SEND_KEY`, `HASNA_MAILERY_SEND_KEY`,
|
|
42
43
|
`HASNA_LOGS_API_TOKEN`, or the matching service env vars before scheduled runs.
|
|
44
|
+
Private probe env output is blocked by default while hosted probe routes remain
|
|
45
|
+
fail-closed; `--allow-blocked-env` is for review artifacts only, not startup.
|
|
43
46
|
|
|
44
47
|
The `uptime cloud ...` commands generate dry-run AWS/private-probe planning artifacts
|
|
45
48
|
only. They do not call AWS, write secrets, or produce an approved deploy script;
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# Third-Party Notices
|
|
2
2
|
|
|
3
|
-
Open Uptime bundles or depends on the following third-party packages.
|
|
3
|
+
Open Uptime bundles or depends on the following third-party packages. The
|
|
4
|
+
versions listed here reflect the checked-in lockfile and release build used for
|
|
5
|
+
the published package; package managers may resolve newer compatible versions
|
|
6
|
+
when installing from semver ranges.
|
|
4
7
|
|
|
5
8
|
## @modelcontextprotocol/sdk
|
|
6
9
|
|
package/dist/api.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");
|
package/dist/cli/index.js
CHANGED
|
@@ -5728,12 +5728,18 @@ var MAX_PROBE_RESULT_FUTURE_MS = 5 * 60000;
|
|
|
5728
5728
|
class UptimeService {
|
|
5729
5729
|
store;
|
|
5730
5730
|
checkRunner;
|
|
5731
|
+
hostedResolveHost;
|
|
5732
|
+
hostedHttpRequest;
|
|
5733
|
+
hostedMaxRedirects;
|
|
5731
5734
|
leaseOwner = `svc_${randomUUID3().replace(/-/g, "").slice(0, 18)}`;
|
|
5732
5735
|
inFlightChecks = new Set;
|
|
5733
5736
|
inFlightReportSchedules = new Set;
|
|
5734
5737
|
constructor(options = {}) {
|
|
5735
5738
|
this.store = options.store ?? new UptimeStore({ mode: "local", ...options });
|
|
5736
5739
|
this.checkRunner = options.checkRunner ?? runMonitorCheck;
|
|
5740
|
+
this.hostedResolveHost = options.hostedResolveHost;
|
|
5741
|
+
this.hostedHttpRequest = options.hostedHttpRequest;
|
|
5742
|
+
this.hostedMaxRedirects = options.hostedMaxRedirects;
|
|
5737
5743
|
}
|
|
5738
5744
|
close() {
|
|
5739
5745
|
this.store.close();
|
|
@@ -5940,39 +5946,7 @@ class UptimeService {
|
|
|
5940
5946
|
const monitor = this.store.getMonitor(idOrName);
|
|
5941
5947
|
if (!monitor)
|
|
5942
5948
|
throw new Error(`Monitor not found: ${idOrName}`);
|
|
5943
|
-
|
|
5944
|
-
throw new Error(`Monitor is disabled: ${monitor.name}`);
|
|
5945
|
-
if (this.inFlightChecks.has(monitor.id))
|
|
5946
|
-
throw new Error(`Monitor check already in progress: ${monitor.name}`);
|
|
5947
|
-
const leaseTtlMs = Math.max(60000, (monitor.retryCount + 1) * monitor.timeoutMs + 1e4);
|
|
5948
|
-
if (!this.store.acquireCheckLease(monitor.id, this.leaseOwner, leaseTtlMs)) {
|
|
5949
|
-
throw new MonitorCheckBusyError(`Monitor check already in progress: ${monitor.name}`);
|
|
5950
|
-
}
|
|
5951
|
-
this.inFlightChecks.add(monitor.id);
|
|
5952
|
-
try {
|
|
5953
|
-
let attemptCount = 0;
|
|
5954
|
-
let last = null;
|
|
5955
|
-
const maxAttempts = Math.max(1, monitor.retryCount + 1);
|
|
5956
|
-
while (attemptCount < maxAttempts) {
|
|
5957
|
-
attemptCount += 1;
|
|
5958
|
-
last = await this.checkRunner(monitor);
|
|
5959
|
-
if (last.status === "up")
|
|
5960
|
-
break;
|
|
5961
|
-
}
|
|
5962
|
-
return this.store.recordCheckResult({
|
|
5963
|
-
monitorId: monitor.id,
|
|
5964
|
-
status: last.status,
|
|
5965
|
-
latencyMs: last.latencyMs,
|
|
5966
|
-
statusCode: last.statusCode ?? null,
|
|
5967
|
-
error: last.error ?? null,
|
|
5968
|
-
evidence: last.evidence ?? null,
|
|
5969
|
-
attemptCount,
|
|
5970
|
-
expectedMonitorRevision: monitor.revision
|
|
5971
|
-
});
|
|
5972
|
-
} finally {
|
|
5973
|
-
this.inFlightChecks.delete(monitor.id);
|
|
5974
|
-
this.store.releaseCheckLease(monitor.id, this.leaseOwner);
|
|
5975
|
-
}
|
|
5949
|
+
return this.recordMonitorCheck(monitor, { hostedTargetPolicy: false });
|
|
5976
5950
|
}
|
|
5977
5951
|
async checkAll() {
|
|
5978
5952
|
if (this.store.mode === "hosted")
|
|
@@ -5984,6 +5958,49 @@ class UptimeService {
|
|
|
5984
5958
|
}
|
|
5985
5959
|
return results;
|
|
5986
5960
|
}
|
|
5961
|
+
async checkHostedPublicMonitor(idOrName, options = {}) {
|
|
5962
|
+
this.assertHostedPublicChecksEnabled();
|
|
5963
|
+
const workspaceId = this.requireHostedWorkerWorkspaceId(options.workspaceId);
|
|
5964
|
+
const monitor = this.store.getMonitor(idOrName, { workspaceId });
|
|
5965
|
+
if (!monitor)
|
|
5966
|
+
throw new Error(`Monitor not found: ${idOrName}`);
|
|
5967
|
+
this.assertHostedPublicMonitor(monitor);
|
|
5968
|
+
const result = await this.recordMonitorCheck(monitor, { hostedTargetPolicy: true });
|
|
5969
|
+
this.auditStore().recordAuditEvent({
|
|
5970
|
+
workspaceId,
|
|
5971
|
+
action: "hosted_public_check.run",
|
|
5972
|
+
resourceType: "monitor",
|
|
5973
|
+
resourceId: monitor.id,
|
|
5974
|
+
message: `Ran hosted public check for ${monitor.name}`,
|
|
5975
|
+
metadata: {
|
|
5976
|
+
checkResultId: result.id,
|
|
5977
|
+
status: result.status,
|
|
5978
|
+
monitorKind: monitor.kind,
|
|
5979
|
+
operatorPath: "hosted_public_check"
|
|
5980
|
+
},
|
|
5981
|
+
actor: "hosted-public-check-worker"
|
|
5982
|
+
});
|
|
5983
|
+
return result;
|
|
5984
|
+
}
|
|
5985
|
+
async runDueHostedPublicChecks(now = new Date, options = {}) {
|
|
5986
|
+
this.assertHostedPublicChecksEnabled();
|
|
5987
|
+
const workspaceId = this.requireHostedWorkerWorkspaceId(options.workspaceId);
|
|
5988
|
+
const due = this.store.listMonitors({ workspaceId }).filter((monitor) => this.isHostedPublicMonitor(monitor) && this.isDue(monitor, now));
|
|
5989
|
+
const results = [];
|
|
5990
|
+
for (const monitor of due) {
|
|
5991
|
+
const current = this.store.getMonitor(monitor.id, { workspaceId });
|
|
5992
|
+
if (!current || !this.isHostedPublicMonitor(current) || !this.isDue(current, now))
|
|
5993
|
+
continue;
|
|
5994
|
+
try {
|
|
5995
|
+
results.push(await this.checkHostedPublicMonitor(current.id, { workspaceId }));
|
|
5996
|
+
} catch (error) {
|
|
5997
|
+
if (error instanceof MonitorCheckBusyError || error instanceof StaleCheckResultError)
|
|
5998
|
+
continue;
|
|
5999
|
+
throw error;
|
|
6000
|
+
}
|
|
6001
|
+
}
|
|
6002
|
+
return results;
|
|
6003
|
+
}
|
|
5987
6004
|
startScheduler(options = {}) {
|
|
5988
6005
|
if (this.store.mode === "hosted")
|
|
5989
6006
|
throw new Error("hosted scheduler requires check_jobs and probes");
|
|
@@ -6029,6 +6046,67 @@ class UptimeService {
|
|
|
6029
6046
|
const last = new Date(monitor.lastCheckedAt).getTime();
|
|
6030
6047
|
return now.getTime() - last >= monitor.intervalSeconds * 1000;
|
|
6031
6048
|
}
|
|
6049
|
+
async recordMonitorCheck(monitor, options) {
|
|
6050
|
+
if (!monitor.enabled)
|
|
6051
|
+
throw new Error(`Monitor is disabled: ${monitor.name}`);
|
|
6052
|
+
if (this.inFlightChecks.has(monitor.id))
|
|
6053
|
+
throw new Error(`Monitor check already in progress: ${monitor.name}`);
|
|
6054
|
+
const leaseTtlMs = Math.max(60000, (monitor.retryCount + 1) * monitor.timeoutMs + 1e4);
|
|
6055
|
+
if (!this.store.acquireCheckLease(monitor.id, this.leaseOwner, leaseTtlMs)) {
|
|
6056
|
+
throw new MonitorCheckBusyError(`Monitor check already in progress: ${monitor.name}`);
|
|
6057
|
+
}
|
|
6058
|
+
this.inFlightChecks.add(monitor.id);
|
|
6059
|
+
try {
|
|
6060
|
+
let attemptCount = 0;
|
|
6061
|
+
let last = null;
|
|
6062
|
+
const maxAttempts = Math.max(1, monitor.retryCount + 1);
|
|
6063
|
+
while (attemptCount < maxAttempts) {
|
|
6064
|
+
attemptCount += 1;
|
|
6065
|
+
last = options.hostedTargetPolicy ? await this.runHostedPublicCheckAttempt(monitor) : await this.checkRunner(monitor);
|
|
6066
|
+
if (last.status === "up")
|
|
6067
|
+
break;
|
|
6068
|
+
}
|
|
6069
|
+
return this.store.recordCheckResult({
|
|
6070
|
+
monitorId: monitor.id,
|
|
6071
|
+
status: last.status,
|
|
6072
|
+
latencyMs: last.latencyMs,
|
|
6073
|
+
statusCode: last.statusCode ?? null,
|
|
6074
|
+
error: last.error ?? null,
|
|
6075
|
+
evidence: last.evidence ?? null,
|
|
6076
|
+
attemptCount,
|
|
6077
|
+
expectedMonitorRevision: monitor.revision
|
|
6078
|
+
});
|
|
6079
|
+
} finally {
|
|
6080
|
+
this.inFlightChecks.delete(monitor.id);
|
|
6081
|
+
this.store.releaseCheckLease(monitor.id, this.leaseOwner);
|
|
6082
|
+
}
|
|
6083
|
+
}
|
|
6084
|
+
runHostedPublicCheckAttempt(monitor) {
|
|
6085
|
+
return runMonitorCheck(monitor, {
|
|
6086
|
+
hostedTargetPolicy: true,
|
|
6087
|
+
resolveHost: this.hostedResolveHost,
|
|
6088
|
+
hostedHttpRequest: this.hostedHttpRequest,
|
|
6089
|
+
maxRedirects: this.hostedMaxRedirects
|
|
6090
|
+
});
|
|
6091
|
+
}
|
|
6092
|
+
assertHostedPublicChecksEnabled() {
|
|
6093
|
+
if (this.store.mode !== "hosted")
|
|
6094
|
+
throw new Error("hosted public checks require hosted mode");
|
|
6095
|
+
}
|
|
6096
|
+
requireHostedWorkerWorkspaceId(workspaceId) {
|
|
6097
|
+
const value = workspaceId?.trim() || process.env.HASNA_UPTIME_WORKSPACE_ID?.trim();
|
|
6098
|
+
if (!value)
|
|
6099
|
+
throw new Error("hosted public checks require a workspace id");
|
|
6100
|
+
return value;
|
|
6101
|
+
}
|
|
6102
|
+
assertHostedPublicMonitor(monitor) {
|
|
6103
|
+
if (!this.isHostedPublicMonitor(monitor)) {
|
|
6104
|
+
throw new Error("hosted public checks support only HTTP and TCP monitors");
|
|
6105
|
+
}
|
|
6106
|
+
}
|
|
6107
|
+
isHostedPublicMonitor(monitor) {
|
|
6108
|
+
return monitor.kind === "http" || monitor.kind === "tcp";
|
|
6109
|
+
}
|
|
6032
6110
|
probeStore() {
|
|
6033
6111
|
if (this.store.mode === "hosted") {
|
|
6034
6112
|
throw new Error("hosted probe APIs require cloud check_jobs, workspace stores, and audit logging");
|
|
@@ -7151,7 +7229,7 @@ function buildAwsDeploymentPlan(options = {}) {
|
|
|
7151
7229
|
const image = clean(options.image, `${imageRepositoryUri}@sha256:<image-digest>`);
|
|
7152
7230
|
const evidenceBucket = clean(options.evidenceBucket, `hasna-${stage}-${prefix}-evidence`);
|
|
7153
7231
|
const hostedSqliteDbPath = clean(options.hostedSqliteDbPath, DEFAULT_HOSTED_SQLITE_DB);
|
|
7154
|
-
const runtimePackageVersion = clean(options.runtimePackageVersion, "0.1.
|
|
7232
|
+
const runtimePackageVersion = clean(options.runtimePackageVersion, "0.1.24");
|
|
7155
7233
|
const protectedAccessMode = options.protectedAccessMode ?? DEFAULT_PROTECTED_ACCESS_MODE;
|
|
7156
7234
|
const protectedAccessUrl = protectedAccessMode === "cloudfront_default_domain" ? "https://<cloudfront-domain>" : `https://${hostname}`;
|
|
7157
7235
|
const cluster = `${prefix}-${stage}`;
|
|
@@ -7396,7 +7474,10 @@ function buildPrivateProbeCloudConfig(options = {}) {
|
|
|
7396
7474
|
}
|
|
7397
7475
|
};
|
|
7398
7476
|
}
|
|
7399
|
-
function renderPrivateProbeEnv(config) {
|
|
7477
|
+
function renderPrivateProbeEnv(config, options = {}) {
|
|
7478
|
+
if (!options.allowBlocked && (!config.canStart || config.blockers.length > 0)) {
|
|
7479
|
+
throw new Error("private probe env output is blocked until hosted probe routes and cloud jobs are implemented");
|
|
7480
|
+
}
|
|
7400
7481
|
const required = ["HASNA_UPTIME_PRIVATE_PROBE_ID"];
|
|
7401
7482
|
const missing = required.filter((key) => !config.env[key]);
|
|
7402
7483
|
if (missing.length > 0) {
|
|
@@ -7439,6 +7520,13 @@ program2.name("uptime").description("Local-first uptime and downtime monitoring"
|
|
|
7439
7520
|
function service() {
|
|
7440
7521
|
return new UptimeService({ mode: "local" });
|
|
7441
7522
|
}
|
|
7523
|
+
function hostedService(opts) {
|
|
7524
|
+
return new UptimeService({
|
|
7525
|
+
mode: "hosted",
|
|
7526
|
+
hostedSqliteDbPath: opts.hostedSqliteDb,
|
|
7527
|
+
allowHostedLocalStore: opts.allowHostedLocalStore
|
|
7528
|
+
});
|
|
7529
|
+
}
|
|
7442
7530
|
function wantsJson(opts) {
|
|
7443
7531
|
return Boolean(opts?.json || program2.opts().json);
|
|
7444
7532
|
}
|
|
@@ -7764,7 +7852,7 @@ cloud.command("plan").description("Generate a dry-run AWS deployment plan").opti
|
|
|
7764
7852
|
fail(error);
|
|
7765
7853
|
}
|
|
7766
7854
|
});
|
|
7767
|
-
cloud.command("private-probe-config").description("Generate hosted-targeted private probe preflight configuration").option("--api-url <url>", "hosted Open Uptime API URL", "https://uptime.example.com/api/v1").option("--workspace-id <id>", "workspace id", "workspace-id").option("--probe-id <id>", "cloud registered private probe id").option("--private-key-file <path>", "private probe key file", "~/.hasna/uptime/probes/private-probe-01.key.pem").option("--machine-id <id>", "machine id", "private-probe-01").option("--log-level <level>", "probe log level", "info").option("--env", "print shell env file instead of summary text").option("-j, --json", "print JSON").action((opts) => {
|
|
7855
|
+
cloud.command("private-probe-config").description("Generate hosted-targeted private probe preflight configuration").option("--api-url <url>", "hosted Open Uptime API URL", "https://uptime.example.com/api/v1").option("--workspace-id <id>", "workspace id", "workspace-id").option("--probe-id <id>", "cloud registered private probe id").option("--private-key-file <path>", "private probe key file", "~/.hasna/uptime/probes/private-probe-01.key.pem").option("--machine-id <id>", "machine id", "private-probe-01").option("--log-level <level>", "probe log level", "info").option("--env", "print shell env file instead of summary text").option("--allow-blocked-env", "print the blocked preflight env anyway for review artifacts; do not start the probe").option("-j, --json", "print JSON").action((opts) => {
|
|
7768
7856
|
try {
|
|
7769
7857
|
const config = buildPrivateProbeCloudConfig({
|
|
7770
7858
|
apiUrl: opts.apiUrl,
|
|
@@ -7775,7 +7863,7 @@ cloud.command("private-probe-config").description("Generate hosted-targeted priv
|
|
|
7775
7863
|
logLevel: opts.logLevel
|
|
7776
7864
|
});
|
|
7777
7865
|
if (opts.env && !wantsJson(opts)) {
|
|
7778
|
-
console.log(renderPrivateProbeEnv(config));
|
|
7866
|
+
console.log(renderPrivateProbeEnv(config, { allowBlocked: opts.allowBlockedEnv }));
|
|
7779
7867
|
return;
|
|
7780
7868
|
}
|
|
7781
7869
|
print(config, renderPrivateProbeConfig(config), opts);
|
|
@@ -7783,6 +7871,22 @@ cloud.command("private-probe-config").description("Generate hosted-targeted priv
|
|
|
7783
7871
|
fail(error);
|
|
7784
7872
|
}
|
|
7785
7873
|
});
|
|
7874
|
+
var cloudPublicChecks = cloud.command("public-checks").description("Run hosted public HTTP/TCP checks against the configured hosted store");
|
|
7875
|
+
cloudPublicChecks.command("run-due").description("Run due hosted public HTTP/TCP checks for one workspace").option("--workspace-id <id>", "workspace id; defaults to HASNA_UPTIME_WORKSPACE_ID").option("--now <iso>", "due timestamp", new Date().toISOString()).option("--hosted-sqlite-db <path>", "hosted SQLite path on cloud-mounted storage").option("--allow-hosted-local-store", "allow hosted mode to use local SQLite as an explicit fallback").option("-j, --json", "print JSON").action(async (opts) => {
|
|
7876
|
+
try {
|
|
7877
|
+
const svc = hostedService({
|
|
7878
|
+
hostedSqliteDb: opts.hostedSqliteDb,
|
|
7879
|
+
allowHostedLocalStore: opts.allowHostedLocalStore
|
|
7880
|
+
});
|
|
7881
|
+
const workspaceId = opts.workspaceId || process.env.HASNA_UPTIME_WORKSPACE_ID;
|
|
7882
|
+
const results = await svc.runDueHostedPublicChecks(new Date(opts.now), { workspaceId });
|
|
7883
|
+
svc.close();
|
|
7884
|
+
const data = { ok: true, workspaceId, checked: results.length, results };
|
|
7885
|
+
print(data, results.length ? renderCheckResults(results) : "No due hosted public checks", opts);
|
|
7886
|
+
} catch (error) {
|
|
7887
|
+
fail(error);
|
|
7888
|
+
}
|
|
7889
|
+
});
|
|
7786
7890
|
program2.command("results").description("List recent check results").option("--monitor <id>", "filter by monitor id").option("--limit <n>", "max rows", parseInteger, 20).option("-j, --json", "print JSON").action((opts) => {
|
|
7787
7891
|
try {
|
|
7788
7892
|
const svc = service();
|
package/dist/cloud-plan.d.ts
CHANGED
|
@@ -137,5 +137,7 @@ export interface PrivateProbeCloudConfig {
|
|
|
137
137
|
}
|
|
138
138
|
export declare function buildAwsDeploymentPlan(options?: AwsDeploymentPlanOptions): AwsDeploymentPlan;
|
|
139
139
|
export declare function buildPrivateProbeCloudConfig(options?: PrivateProbeCloudConfigOptions): PrivateProbeCloudConfig;
|
|
140
|
-
export declare function renderPrivateProbeEnv(config: PrivateProbeCloudConfig
|
|
140
|
+
export declare function renderPrivateProbeEnv(config: PrivateProbeCloudConfig, options?: {
|
|
141
|
+
allowBlocked?: boolean;
|
|
142
|
+
}): string;
|
|
141
143
|
//# sourceMappingURL=cloud-plan.d.ts.map
|
package/dist/cloud-plan.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-plan.d.ts","sourceRoot":"","sources":["../src/cloud-plan.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"cloud-plan.d.ts","sourceRoot":"","sources":["../src/cloud-plan.ts"],"names":[],"mappings":"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"}
|
package/dist/cloud-plan.js
CHANGED
|
@@ -21,7 +21,7 @@ function buildAwsDeploymentPlan(options = {}) {
|
|
|
21
21
|
const image = clean(options.image, `${imageRepositoryUri}@sha256:<image-digest>`);
|
|
22
22
|
const evidenceBucket = clean(options.evidenceBucket, `hasna-${stage}-${prefix}-evidence`);
|
|
23
23
|
const hostedSqliteDbPath = clean(options.hostedSqliteDbPath, DEFAULT_HOSTED_SQLITE_DB);
|
|
24
|
-
const runtimePackageVersion = clean(options.runtimePackageVersion, "0.1.
|
|
24
|
+
const runtimePackageVersion = clean(options.runtimePackageVersion, "0.1.24");
|
|
25
25
|
const protectedAccessMode = options.protectedAccessMode ?? DEFAULT_PROTECTED_ACCESS_MODE;
|
|
26
26
|
const protectedAccessUrl = protectedAccessMode === "cloudfront_default_domain" ? "https://<cloudfront-domain>" : `https://${hostname}`;
|
|
27
27
|
const cluster = `${prefix}-${stage}`;
|
|
@@ -266,7 +266,10 @@ function buildPrivateProbeCloudConfig(options = {}) {
|
|
|
266
266
|
}
|
|
267
267
|
};
|
|
268
268
|
}
|
|
269
|
-
function renderPrivateProbeEnv(config) {
|
|
269
|
+
function renderPrivateProbeEnv(config, options = {}) {
|
|
270
|
+
if (!options.allowBlocked && (!config.canStart || config.blockers.length > 0)) {
|
|
271
|
+
throw new Error("private probe env output is blocked until hosted probe routes and cloud jobs are implemented");
|
|
272
|
+
}
|
|
270
273
|
const required = ["HASNA_UPTIME_PRIVATE_PROBE_ID"];
|
|
271
274
|
const missing = required.filter((key) => !config.env[key]);
|
|
272
275
|
if (missing.length > 0) {
|
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");
|
|
@@ -4557,7 +4635,7 @@ function buildAwsDeploymentPlan(options = {}) {
|
|
|
4557
4635
|
const image = clean(options.image, `${imageRepositoryUri}@sha256:<image-digest>`);
|
|
4558
4636
|
const evidenceBucket = clean(options.evidenceBucket, `hasna-${stage}-${prefix}-evidence`);
|
|
4559
4637
|
const hostedSqliteDbPath = clean(options.hostedSqliteDbPath, DEFAULT_HOSTED_SQLITE_DB);
|
|
4560
|
-
const runtimePackageVersion = clean(options.runtimePackageVersion, "0.1.
|
|
4638
|
+
const runtimePackageVersion = clean(options.runtimePackageVersion, "0.1.24");
|
|
4561
4639
|
const protectedAccessMode = options.protectedAccessMode ?? DEFAULT_PROTECTED_ACCESS_MODE;
|
|
4562
4640
|
const protectedAccessUrl = protectedAccessMode === "cloudfront_default_domain" ? "https://<cloudfront-domain>" : `https://${hostname}`;
|
|
4563
4641
|
const cluster = `${prefix}-${stage}`;
|
|
@@ -4802,7 +4880,10 @@ function buildPrivateProbeCloudConfig(options = {}) {
|
|
|
4802
4880
|
}
|
|
4803
4881
|
};
|
|
4804
4882
|
}
|
|
4805
|
-
function renderPrivateProbeEnv(config) {
|
|
4883
|
+
function renderPrivateProbeEnv(config, options = {}) {
|
|
4884
|
+
if (!options.allowBlocked && (!config.canStart || config.blockers.length > 0)) {
|
|
4885
|
+
throw new Error("private probe env output is blocked until hosted probe routes and cloud jobs are implemented");
|
|
4886
|
+
}
|
|
4806
4887
|
const required = ["HASNA_UPTIME_PRIVATE_PROBE_ID"];
|
|
4807
4888
|
const missing = required.filter((key) => !config.env[key]);
|
|
4808
4889
|
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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"}
|
package/dist/service.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");
|
|
@@ -8,7 +8,8 @@ call AWS or mutate infrastructure.
|
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
uptime cloud plan --json > open-uptime-aws-plan.json
|
|
11
|
-
uptime cloud private-probe-config --probe-id prb_private_01 --machine-id private-probe-01 --
|
|
11
|
+
uptime cloud private-probe-config --probe-id prb_private_01 --machine-id private-probe-01 --json > private-probe-01-preflight.json
|
|
12
|
+
uptime cloud private-probe-config --probe-id prb_private_01 --machine-id private-probe-01 --env --allow-blocked-env > private-probe-01-review-only.env
|
|
12
13
|
```
|
|
13
14
|
|
|
14
15
|
Public package defaults are placeholders:
|
|
@@ -33,8 +34,10 @@ The app repo includes a hosted runtime `Dockerfile` and Terraform/OpenTofu
|
|
|
33
34
|
starter files in `infra/aws`. The plan output points to these files and keeps
|
|
34
35
|
`applyAllowed: false`.
|
|
35
36
|
|
|
36
|
-
`uptime cloud private-probe-config --env`
|
|
37
|
-
|
|
37
|
+
`uptime cloud private-probe-config --env` is blocked by default while hosted
|
|
38
|
+
probe routes remain fail-closed. It requires both a real `--probe-id` and the
|
|
39
|
+
explicit `--allow-blocked-env` review override; do not use that env output to
|
|
40
|
+
start a private probe until the JSON output says `canStart: true`.
|
|
38
41
|
|
|
39
42
|
## Preflight
|
|
40
43
|
|
|
@@ -398,11 +401,13 @@ routes are backed by cloud check jobs and cloud audit rows.
|
|
|
398
401
|
URLs, or probe private keys in task definitions. Use ECS `secrets.valueFrom`
|
|
399
402
|
refs such as `HASNA_UPTIME_HOSTED_TOKEN`.
|
|
400
403
|
- Do not run public probe workers against private targets.
|
|
401
|
-
- Do not enable public probe workers until their cloud check-job path calls
|
|
402
|
-
|
|
403
|
-
smokes for denied DNS answers, redirect-to-denied targets, and
|
|
404
|
-
pinning. The SDK
|
|
405
|
-
|
|
404
|
+
- Do not enable public probe workers until their cloud check-job path calls the
|
|
405
|
+
hosted public-check runner, records target-policy decision evidence, and
|
|
406
|
+
passes AWS smokes for denied DNS answers, redirect-to-denied targets, and
|
|
407
|
+
address pinning. The SDK and `uptime cloud public-checks run-due` path now
|
|
408
|
+
handle execution-time DNS and redirect enforcement for bounded smokes, but a
|
|
409
|
+
sustained public-probe worker loop is not active until it is wired to cloud
|
|
410
|
+
leases.
|
|
406
411
|
- Do not enable scheduler, public-probe, reporter, or migration workers against
|
|
407
412
|
the EFS SQLite bridge; those services need Postgres/cloud leases first.
|
|
408
413
|
- Do not expose dashboard/API routes without hosted auth and workspace checks.
|
|
@@ -122,11 +122,12 @@ or delete workspace B data.
|
|
|
122
122
|
The target-state architecture uses one shared target policy at both
|
|
123
123
|
configuration time and execution time. The current hosted API implements
|
|
124
124
|
configuration-time checks for direct targets, and the SDK exposes
|
|
125
|
-
`runHostedHttpCheck`
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
125
|
+
`runHostedHttpCheck` plus a bounded hosted public-check service/CLI path for
|
|
126
|
+
workspace-scoped HTTP/TCP checks. Those paths perform runtime DNS resolution,
|
|
127
|
+
address pinning, redirect validation, DNS-rebinding protection, and
|
|
128
|
+
decision-record evidence. Long-running public probe execution stays disabled
|
|
129
|
+
until cloud check-job leases and the public-probe worker loop are wired to that
|
|
130
|
+
runner and validated in AWS.
|
|
130
131
|
|
|
131
132
|
Public probes must deny:
|
|
132
133
|
|
|
@@ -428,8 +429,10 @@ ECS/API/RDS/S3/probe lag/job backlog/delivery failures, and rollback commands.
|
|
|
428
429
|
- Hosted API reads are protected only by a broad bootstrap token, and the hosted
|
|
429
430
|
dashboard shell still fails closed; production-grade identity/RBAC is not
|
|
430
431
|
implemented yet.
|
|
431
|
-
- Outbound target policy for hosted HTTP
|
|
432
|
-
cloud public-
|
|
432
|
+
- Outbound target policy for hosted HTTP/TCP checks exists in the SDK and the
|
|
433
|
+
`uptime cloud public-checks run-due` operator path. The cloud public-probe
|
|
434
|
+
worker loop, durable check-job lease path, and sustained ECS liveness are not
|
|
435
|
+
wired yet.
|
|
433
436
|
- `@hasna/cloud` hybrid mode still returns SQLite, so it is not cloud-primary.
|
|
434
437
|
- The local cloud config currently points at a stale/non-resolving database host.
|
|
435
438
|
- Todos has unresolved conflicts that must be reconciled before cloud cutover.
|
|
@@ -19,7 +19,7 @@ alb_ingress_cidr_blocks = []
|
|
|
19
19
|
private_subnet_ids = ["subnet-replace-private-a", "subnet-replace-private-b"]
|
|
20
20
|
private_route_table_ids = ["rtb-replace-private"]
|
|
21
21
|
container_image = "123456789012.dkr.ecr.us-east-1.amazonaws.com/open-uptime@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
22
|
-
runtime_package_version = "0.1.
|
|
22
|
+
runtime_package_version = "0.1.24"
|
|
23
23
|
certificate_arn = null
|
|
24
24
|
hosted_zone_id = null
|
|
25
25
|
app_env_secret_arn = "arn:aws:secretsmanager:us-east-1:123456789012:secret:open-uptime/prod/app/env"
|
package/infra/aws/variables.tf
CHANGED
|
@@ -201,7 +201,7 @@ variable "container_image" {
|
|
|
201
201
|
variable "runtime_package_version" {
|
|
202
202
|
description = "Published @hasna/uptime package version that CodeBuild should build into the ECR image."
|
|
203
203
|
type = string
|
|
204
|
-
default = "0.1.
|
|
204
|
+
default = "0.1.24"
|
|
205
205
|
|
|
206
206
|
validation {
|
|
207
207
|
condition = can(regex("^[0-9]+\\.[0-9]+\\.[0-9]+(-[0-9A-Za-z.-]+)?$", var.runtime_package_version))
|
package/package.json
CHANGED