@hasna/uptime 0.1.11 → 0.1.12

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.
@@ -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.11");
24
+ const runtimePackageVersion = clean(options.runtimePackageVersion, "0.1.12");
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}`;
@@ -163,7 +163,7 @@ function buildAwsDeploymentPlan(options = {}) {
163
163
  "The infrastructure owner repository was not found in this workspace.",
164
164
  "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.",
165
165
  "Hosted production auth/RBAC must replace broad static hosted-token operation before exposure.",
166
- "Public probe execution still needs DNS, redirect, and rebinding SSRF enforcement plus cloud check-job leases.",
166
+ "Public probe execution still needs cloud check-job leases wired to runHostedHttpCheck and live policy-decision log evidence.",
167
167
  "Private probe enrollment, claim, submit, heartbeat, revocation, and rotation are not cloud-backed yet."
168
168
  ],
169
169
  requiredEvidence: [
package/dist/imports.js CHANGED
@@ -14,6 +14,40 @@ var MAX_RESULT_LIMIT = 1000;
14
14
  // src/target-policy.ts
15
15
  import net from "net";
16
16
  var SECRET_PARAM_PATTERN = /(token|secret|password|passwd|api[_-]?key|access[_-]?token|auth|credential|session)/i;
17
+ var DENIED_IPV4_CIDRS = [
18
+ ["0.0.0.0", 8],
19
+ ["10.0.0.0", 8],
20
+ ["100.64.0.0", 10],
21
+ ["127.0.0.0", 8],
22
+ ["169.254.0.0", 16],
23
+ ["172.16.0.0", 12],
24
+ ["192.0.0.0", 24],
25
+ ["192.0.2.0", 24],
26
+ ["192.88.99.0", 24],
27
+ ["192.168.0.0", 16],
28
+ ["198.18.0.0", 15],
29
+ ["198.51.100.0", 24],
30
+ ["203.0.113.0", 24],
31
+ ["224.0.0.0", 4],
32
+ ["240.0.0.0", 4]
33
+ ];
34
+ var DENIED_IPV6_CIDRS = [
35
+ ["::", 128],
36
+ ["::1", 128],
37
+ ["64:ff9b::", 96],
38
+ ["64:ff9b:1::", 48],
39
+ ["100::", 64],
40
+ ["100:0:0:1::", 64],
41
+ ["2001::", 23],
42
+ ["2001:db8::", 32],
43
+ ["2002::", 16],
44
+ ["2620:4f:8000::", 48],
45
+ ["3fff::", 20],
46
+ ["5f00::", 16],
47
+ ["fc00::", 7],
48
+ ["fe80::", 10],
49
+ ["ff00::", 8]
50
+ ];
17
51
  function assertHostedTargetAllowed(target) {
18
52
  if (target.kind === "http" || target.kind === "browser_page") {
19
53
  if (!target.url)
@@ -51,7 +85,7 @@ function assertHostedHttpUrlAllowed(value) {
51
85
  assertHostedHostAllowed(parsed.hostname, "HTTP host");
52
86
  }
53
87
  function assertHostedHostAllowed(hostname, label = "host") {
54
- const host = normalizeHost(hostname);
88
+ const host = normalizeHostedHost(hostname);
55
89
  if (!host)
56
90
  throw new Error(`${label} is required`);
57
91
  if (host === "localhost" || host.endsWith(".localhost")) {
@@ -68,39 +102,88 @@ function assertHostedHostAllowed(hostname, label = "host") {
68
102
  throw new Error(`${label} is not allowed in hosted mode: private or reserved IPv6`);
69
103
  }
70
104
  }
71
- function normalizeHost(hostname) {
105
+ function assertHostedResolvedAddressesAllowed(hostname, addresses, label = "resolved address") {
106
+ if (addresses.length === 0) {
107
+ throw new Error(`${label} is not allowed in hosted mode: DNS returned no addresses for ${normalizeHostedHost(hostname) || "host"}`);
108
+ }
109
+ for (const entry of addresses) {
110
+ assertHostedAddressAllowed(entry.address, label);
111
+ }
112
+ }
113
+ function assertHostedAddressAllowed(address, label = "resolved address") {
114
+ const host = normalizeHostedHost(address);
115
+ const ipVersion = net.isIP(host);
116
+ if (ipVersion === 4 && isDeniedIpv4(host)) {
117
+ throw new Error(`${label} is not allowed in hosted mode: private or reserved IPv4`);
118
+ }
119
+ if (ipVersion === 6 && isDeniedIpv6(host)) {
120
+ throw new Error(`${label} is not allowed in hosted mode: private or reserved IPv6`);
121
+ }
122
+ if (ipVersion === 0) {
123
+ throw new Error(`${label} is not allowed in hosted mode: DNS returned a non-IP address`);
124
+ }
125
+ }
126
+ function normalizeHostedHost(hostname) {
72
127
  return hostname.trim().toLowerCase().replace(/^\[|\]$/g, "").replace(/\.$/, "");
73
128
  }
74
129
  function isDeniedIpv4(ip) {
75
- const parts = ip.split(".").map((part) => Number(part));
76
- if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) {
130
+ const parts = parseIpv4Words(ip);
131
+ if (!parts)
77
132
  return true;
78
- }
79
- const [a, b] = parts;
80
- return a === 0 || a === 10 || a === 127 || a === 100 && b >= 64 && b <= 127 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a >= 224;
133
+ return DENIED_IPV4_CIDRS.some(([base, prefix]) => ipv4MatchesCidr(parts, parseIpv4Words(base), prefix));
81
134
  }
82
135
  function isDeniedIpv6(ip) {
83
136
  const normalized = ip.toLowerCase();
84
- const mappedIpv4 = ipv4FromMappedIpv6(normalized);
137
+ const words = parseIpv6Words(normalized);
138
+ if (!words)
139
+ return true;
140
+ const mappedIpv4 = ipv4FromMappedIpv6Words(words);
85
141
  if (mappedIpv4)
86
142
  return isDeniedIpv4(mappedIpv4);
87
- const words = parseIpv6Words(normalized);
88
- return normalized === "::" || normalized === "::1" || words !== null && (words[0] & 65472) === 65152 || normalized.startsWith("fc") || normalized.startsWith("fd") || normalized.startsWith("ff");
143
+ return isIpv4CompatibleIpv6(words) || DENIED_IPV6_CIDRS.some(([base, prefix]) => ipv6MatchesCidr(words, parseIpv6Words(base), prefix));
89
144
  }
90
- function ipv4FromMappedIpv6(ip) {
91
- const words = parseIpv6Words(ip);
145
+ function isIpv4CompatibleIpv6(words) {
92
146
  if (!words)
93
- return null;
147
+ return false;
148
+ if (!words.slice(0, 6).every((word) => word === 0))
149
+ return false;
150
+ if (words[6] === 0 && (words[7] === 0 || words[7] === 1))
151
+ return false;
152
+ return true;
153
+ }
154
+ function ipv4FromMappedIpv6Words(words) {
94
155
  if (words[0] !== 0 || words[1] !== 0 || words[2] !== 0 || words[3] !== 0 || words[4] !== 0 || words[5] !== 65535) {
95
156
  return null;
96
157
  }
158
+ return ipv4FromWords(words[6], words[7]);
159
+ }
160
+ function ipv4FromWords(high, low) {
97
161
  return [
98
- words[6] >> 8,
99
- words[6] & 255,
100
- words[7] >> 8,
101
- words[7] & 255
162
+ high >> 8,
163
+ high & 255,
164
+ low >> 8,
165
+ low & 255
102
166
  ].join(".");
103
167
  }
168
+ function ipv4MatchesCidr(parts, base, prefix) {
169
+ const mask = prefix === 0 ? 0 : 4294967295 << 32 - prefix >>> 0;
170
+ return (ipv4ToNumber(parts) & mask) >>> 0 === (ipv4ToNumber(base) & mask) >>> 0;
171
+ }
172
+ function ipv4ToNumber(parts) {
173
+ return (parts[0] << 24 >>> 0 | parts[1] << 16 | parts[2] << 8 | parts[3]) >>> 0;
174
+ }
175
+ function ipv6MatchesCidr(words, base, prefix) {
176
+ const fullWords = Math.floor(prefix / 16);
177
+ for (let index = 0;index < fullWords; index += 1) {
178
+ if (words[index] !== base[index])
179
+ return false;
180
+ }
181
+ const remainingBits = prefix % 16;
182
+ if (remainingBits === 0)
183
+ return true;
184
+ const mask = 65535 << 16 - remainingBits & 65535;
185
+ return (words[fullWords] & mask) === (base[fullWords] & mask);
186
+ }
104
187
  function parseIpv6Words(value) {
105
188
  let ip = value.toLowerCase();
106
189
  const zoneIndex = ip.indexOf("%");
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { createUptimeClient, UptimeService } from "./service.js";
2
2
  export { UptimeStore } from "./store.js";
3
- export { runBrowserPageCheck, runMonitorCheck, runHttpCheck, runTcpCheck } from "./checks.js";
3
+ export { isBrowserPageEvidence, isHttpTargetPolicyEvidence, normalizeHttpTargetPolicyEvidence, runBrowserPageCheck, runHostedHttpCheck, runMonitorCheck, runHttpCheck, runTcpCheck, } from "./checks.js";
4
4
  export { createApiHandler, serveUptime } from "./api.js";
5
5
  export { applyImport, previewImport, rollbackImport } from "./imports.js";
6
6
  export { buildUptimeReport, sendUptimeReport } from "./report.js";
@@ -8,9 +8,9 @@ export { generateProbeKeyPair, probePublicKeyFingerprint, probeResultSigningPayl
8
8
  export { buildAwsDeploymentPlan, buildPrivateProbeCloudConfig, renderPrivateProbeEnv } from "./cloud-plan.js";
9
9
  export { uptimeHome, uptimeDbPath, uptimeHostedFallbackDbPath, ensureUptimeHome } from "./paths.js";
10
10
  export type { UptimeBackup, UptimeBackupCheck, UptimeRuntimeMode, UptimeStoreOptions, MonitorProvenance, SaveImportBatchInput, StoredImportBatch, UpsertMonitorProvenanceInput, } from "./store.js";
11
- export type { BrowserPageRunner, BrowserPageRunnerResult, FetchLike, } from "./checks.js";
11
+ export type { BrowserPageRunner, BrowserPageRunnerResult, FetchLike, HostedDnsResolver, HostedHttpCheckOptions, HostedHttpRequestContext, HostedHttpRequestLike, HostedHttpResponse, MonitorCheckOptions, } from "./checks.js";
12
12
  export type { ImportAction, ImportApplyItem, ImportApplyResult, ImportCandidate, ImportPreview, ImportPreviewItem, ImportRequest, ImportRollbackItem, ImportRollbackResult, ImportSource, } from "./imports.js";
13
- export type { BrowserFailedRequest, BrowserPageEvidence, AuditEvent, CheckAttemptResult, CheckEvidence, CheckResult, CheckStatus, CreateMonitorKind, CreateMonitorInput, CreateReportScheduleInput, ImportedMonitorInput, ImportedUpdateMonitorInput, EvidenceArtifact, Incident, IncidentStatus, ListAuditEventsOptions, ListReportRunsOptions, ListResultsOptions, Monitor, MonitorKind, MonitorStatus, MonitorSummary, ProbeCheckJob, ProbeCheckJobStatus, ProbeIdentity, ProbeResultSubmission, ProbeSubmissionReceipt, RecordAuditEventInput, ReportDeliveryChannel, ReportDeliveryRecord, ReportEmailChannelConfig, ReportLogsChannelConfig, ReportRun, ReportRunStatus, ReportSchedule, ReportScheduleChannels, ReportScheduleStatus, ReportSmsChannelConfig, SchedulerHandle, UpdateMonitorInput, UpdateReportScheduleInput, UptimeSummary, } from "./types.js";
13
+ export type { BrowserFailedRequest, BrowserPageEvidence, AuditEvent, CheckAttemptResult, CheckEvidence, CheckResult, CheckStatus, CreateMonitorKind, CreateMonitorInput, CreateReportScheduleInput, ImportedMonitorInput, ImportedUpdateMonitorInput, EvidenceArtifact, HttpTargetPolicyDecision, HttpTargetPolicyEvidence, Incident, IncidentStatus, ListAuditEventsOptions, ListReportRunsOptions, ListResultsOptions, Monitor, MonitorKind, MonitorStatus, MonitorSummary, ProbeCheckJob, ProbeCheckJobStatus, ProbeIdentity, ProbeResultSubmission, ProbeSubmissionReceipt, RecordAuditEventInput, ReportDeliveryChannel, ReportDeliveryRecord, ReportEmailChannelConfig, ReportLogsChannelConfig, ReportRun, ReportRunStatus, ReportSchedule, ReportScheduleChannels, ReportScheduleStatus, ReportSmsChannelConfig, SchedulerHandle, UpdateMonitorInput, UpdateReportScheduleInput, UptimeSummary, } from "./types.js";
14
14
  export type { ProbeKeyPair, ProbeSigningInput } from "./probes.js";
15
15
  export type { AwsDeploymentPlan, AwsDeploymentPlanOptions, AwsServicePlan, PrivateProbeCloudConfig, PrivateProbeCloudConfigOptions, } from "./cloud-plan.js";
16
16
  export type { BuildUptimeReportOptions, SendUptimeReportOptions, UptimeEmailReportTarget, UptimeLogsReportTarget, UptimeReport, UptimeReportDelivery, UptimeSmsReportTarget, } from "./report.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC9F,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACtJ,OAAO,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAC9G,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,0BAA0B,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACpG,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,4BAA4B,GAC7B,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,iBAAiB,EACjB,uBAAuB,EACvB,SAAS,GACV,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,GACb,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,yBAAyB,EACzB,oBAAoB,EACpB,0BAA0B,EAC1B,gBAAgB,EAChB,QAAQ,EACR,cAAc,EACd,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,OAAO,EACP,WAAW,EACX,aAAa,EACb,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,wBAAwB,EACxB,uBAAuB,EACvB,SAAS,EACT,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,kBAAkB,EAClB,yBAAyB,EACzB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnE,YAAY,EACV,iBAAiB,EACjB,wBAAwB,EACxB,cAAc,EACd,uBAAuB,EACvB,8BAA8B,GAC/B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACtB,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,iCAAiC,EACjC,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACtJ,OAAO,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAC9G,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,0BAA0B,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACpG,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,4BAA4B,GAC7B,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,iBAAiB,EACjB,uBAAuB,EACvB,SAAS,EACT,iBAAiB,EACjB,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,GACb,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,yBAAyB,EACzB,oBAAoB,EACpB,0BAA0B,EAC1B,gBAAgB,EAChB,wBAAwB,EACxB,wBAAwB,EACxB,QAAQ,EACR,cAAc,EACd,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,OAAO,EACP,WAAW,EACX,aAAa,EACb,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,wBAAwB,EACxB,uBAAuB,EACvB,SAAS,EACT,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,kBAAkB,EAClB,yBAAyB,EACzB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnE,YAAY,EACV,iBAAiB,EACjB,wBAAwB,EACxB,cAAc,EACd,uBAAuB,EACvB,8BAA8B,GAC/B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACtB,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,aAAa,CAAC"}