@hasna/uptime 0.1.6 → 0.1.8
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/.dockerignore +0 -1
- package/CHANGELOG.md +35 -1
- package/Dockerfile +2 -1
- package/Dockerfile.package +22 -0
- package/README.md +13 -1
- package/dist/api.d.ts +2 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +81 -12
- package/dist/cli/index.js +148 -51
- package/dist/cloud-plan.d.ts +15 -4
- package/dist/cloud-plan.d.ts.map +1 -1
- package/dist/cloud-plan.js +55 -35
- package/dist/index.js +136 -47
- package/dist/mcp/index.js +38 -8
- package/dist/service.d.ts +1 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +38 -8
- package/dist/store.d.ts +3 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +40 -9
- package/docs/aws-deployment-runbook.md +44 -22
- package/infra/aws/README.md +27 -6
- package/infra/aws/main.tf +374 -36
- package/infra/aws/outputs.tf +20 -0
- package/infra/aws/terraform.tfvars.example +13 -12
- package/infra/aws/variables.tf +48 -22
- package/package.json +2 -1
package/dist/mcp/index.js
CHANGED
|
@@ -15097,7 +15097,7 @@ function stableJson(value) {
|
|
|
15097
15097
|
}
|
|
15098
15098
|
|
|
15099
15099
|
// src/store.ts
|
|
15100
|
-
import { copyFileSync, existsSync, mkdirSync, statSync } from "fs";
|
|
15100
|
+
import { copyFileSync, existsSync, mkdirSync, statfsSync, statSync } from "fs";
|
|
15101
15101
|
import { dirname, join as join2 } from "path";
|
|
15102
15102
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
15103
15103
|
import { Database } from "bun:sqlite";
|
|
@@ -15116,6 +15116,8 @@ function uptimeHostedFallbackDbPath() {
|
|
|
15116
15116
|
}
|
|
15117
15117
|
|
|
15118
15118
|
// src/store.ts
|
|
15119
|
+
var DEFAULT_HOSTED_SQLITE_DB_PATH = "/data/uptime/uptime.db";
|
|
15120
|
+
var NFS_SUPER_MAGIC = 26985;
|
|
15119
15121
|
var SECRET_URL_PARAM_PATTERN = /(token|secret|password|passwd|api[_-]?key|access[_-]?token|auth|credential|session)/i;
|
|
15120
15122
|
var REQUIRED_TABLES = [
|
|
15121
15123
|
"schema_migrations",
|
|
@@ -15152,18 +15154,39 @@ class UptimeStore {
|
|
|
15152
15154
|
this.mode = resolveRuntimeMode(options.mode ?? "local");
|
|
15153
15155
|
const cloudDatabaseUrl = options.cloudDatabaseUrl ?? process.env.HASNA_UPTIME_DATABASE_URL;
|
|
15154
15156
|
if (this.mode === "hosted" && cloudDatabaseUrl) {
|
|
15155
|
-
throw new Error("hosted
|
|
15157
|
+
throw new Error("hosted Postgres adapter is not implemented yet; use HASNA_UPTIME_HOSTED_SQLITE_DB on cloud-mounted storage for the current hosted deployment path");
|
|
15156
15158
|
}
|
|
15157
|
-
|
|
15158
|
-
|
|
15159
|
+
const hostedSqliteDbPath = options.hostedSqliteDbPath ?? process.env.HASNA_UPTIME_HOSTED_SQLITE_DB;
|
|
15160
|
+
if (this.mode === "hosted" && hostedSqliteDbPath) {
|
|
15161
|
+
if (hostedSqliteDbPath === ":memory:" || !hostedSqliteDbPath.startsWith("/")) {
|
|
15162
|
+
throw new Error("HASNA_UPTIME_HOSTED_SQLITE_DB must be an absolute path on mounted cloud storage");
|
|
15163
|
+
}
|
|
15164
|
+
const approvedHostedPath = hostedSqliteDbPath === DEFAULT_HOSTED_SQLITE_DB_PATH;
|
|
15165
|
+
if (!approvedHostedPath && !allowHostedLocalStore(options.allowHostedLocalStore)) {
|
|
15166
|
+
throw new Error(`HASNA_UPTIME_HOSTED_SQLITE_DB must be ${DEFAULT_HOSTED_SQLITE_DB_PATH}; set HASNA_UPTIME_ALLOW_HOSTED_LOCAL_STORE=1 only for explicit local fallback testing`);
|
|
15167
|
+
}
|
|
15168
|
+
const verifiedCloudMount = approvedHostedPath && isNfsMount(dirname(hostedSqliteDbPath));
|
|
15169
|
+
if (approvedHostedPath && !verifiedCloudMount && !allowHostedLocalStore(options.allowHostedLocalStore)) {
|
|
15170
|
+
throw new Error(`${DEFAULT_HOSTED_SQLITE_DB_PATH} must be on a mounted EFS/NFS filesystem; refusing to create hosted task-local SQLite`);
|
|
15171
|
+
}
|
|
15172
|
+
this.dataMode = verifiedCloudMount ? "hosted-efs-sqlite" : "hosted-local-sqlite";
|
|
15173
|
+
this.dbPath = hostedSqliteDbPath;
|
|
15174
|
+
} else if (this.mode === "hosted") {
|
|
15175
|
+
if (!allowHostedLocalStore(options.allowHostedLocalStore)) {
|
|
15176
|
+
throw new Error("hosted mode requires HASNA_UPTIME_HOSTED_SQLITE_DB on mounted cloud storage; set HASNA_UPTIME_ALLOW_HOSTED_LOCAL_STORE=1 only for explicit local fallback testing");
|
|
15177
|
+
}
|
|
15178
|
+
this.dataMode = "hosted-local-sqlite";
|
|
15179
|
+
this.dbPath = options.dbPath ?? uptimeHostedFallbackDbPath();
|
|
15180
|
+
} else {
|
|
15181
|
+
this.dataMode = "local-sqlite";
|
|
15182
|
+
this.dbPath = options.dbPath ?? uptimeDbPath();
|
|
15159
15183
|
}
|
|
15160
|
-
|
|
15161
|
-
this.dbPath = options.dbPath ?? (this.mode === "hosted" ? uptimeHostedFallbackDbPath() : uptimeDbPath());
|
|
15162
|
-
if (this.dbPath !== ":memory:") {
|
|
15184
|
+
if (this.dbPath !== ":memory:" && this.dataMode !== "hosted-efs-sqlite") {
|
|
15163
15185
|
mkdirSync(dirname(this.dbPath), { recursive: true });
|
|
15164
15186
|
}
|
|
15165
15187
|
this.db = new Database(this.dbPath, { create: true });
|
|
15166
|
-
this.db.run("PRAGMA journal_mode = WAL");
|
|
15188
|
+
this.db.run(this.dataMode === "hosted-efs-sqlite" ? "PRAGMA journal_mode = DELETE" : "PRAGMA journal_mode = WAL");
|
|
15189
|
+
this.db.run("PRAGMA busy_timeout = 5000");
|
|
15167
15190
|
this.db.run("PRAGMA foreign_keys = ON");
|
|
15168
15191
|
this.migrate();
|
|
15169
15192
|
}
|
|
@@ -16043,6 +16066,13 @@ function resolveRuntimeMode(mode) {
|
|
|
16043
16066
|
function allowHostedLocalStore(value) {
|
|
16044
16067
|
return value === true || process.env.HASNA_UPTIME_ALLOW_HOSTED_LOCAL_STORE === "1";
|
|
16045
16068
|
}
|
|
16069
|
+
function isNfsMount(path) {
|
|
16070
|
+
try {
|
|
16071
|
+
return statfsSync(path).type === NFS_SUPER_MAGIC;
|
|
16072
|
+
} catch {
|
|
16073
|
+
return false;
|
|
16074
|
+
}
|
|
16075
|
+
}
|
|
16046
16076
|
function verifyBackupFile(backupPath) {
|
|
16047
16077
|
const db = new Database(backupPath, { readonly: true });
|
|
16048
16078
|
try {
|
package/dist/service.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface UptimeServiceOptions extends UptimeStoreOptions {
|
|
|
9
9
|
export interface UptimeStoreLike {
|
|
10
10
|
readonly dbPath: string;
|
|
11
11
|
readonly mode: "local" | "hosted";
|
|
12
|
-
readonly dataMode: "local-sqlite" | "hosted-local-sqlite";
|
|
12
|
+
readonly dataMode: "local-sqlite" | "hosted-local-sqlite" | "hosted-efs-sqlite";
|
|
13
13
|
close(): void;
|
|
14
14
|
createMonitor(input: ImportedMonitorInput, options?: {
|
|
15
15
|
allowBrowserPage?: boolean;
|
package/dist/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAEA,OAAO,EAA8C,KAAK,iBAAiB,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAErK,OAAO,EAAsC,KAAK,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,KAAK,iBAAiB,EAAE,KAAK,4BAA4B,EAAE,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAClP,OAAO,EAAuC,KAAK,wBAAwB,EAAE,KAAK,uBAAuB,EAAE,KAAK,YAAY,EAAE,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC7K,OAAO,KAAK,EACV,UAAU,EACV,kBAAkB,EAClB,WAAW,EACX,yBAAyB,EACzB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,oBAAoB,EACpB,0BAA0B,EAC1B,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,OAAO,EACP,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,SAAS,EACT,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,yBAAyB,EACzB,aAAa,EACd,MAAM,YAAY,CAAC;AAKpB,MAAM,WAAW,oBAAqB,SAAQ,kBAAkB;IAC9D,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACjE;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,cAAc,GAAG,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|
package/dist/service.js
CHANGED
|
@@ -820,10 +820,12 @@ function ensureUptimeHome() {
|
|
|
820
820
|
}
|
|
821
821
|
|
|
822
822
|
// src/store.ts
|
|
823
|
-
import { copyFileSync, existsSync, mkdirSync as mkdirSync2, statSync } from "fs";
|
|
823
|
+
import { copyFileSync, existsSync, mkdirSync as mkdirSync2, statfsSync, statSync } from "fs";
|
|
824
824
|
import { dirname, join as join2 } from "path";
|
|
825
825
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
826
826
|
import { Database } from "bun:sqlite";
|
|
827
|
+
var DEFAULT_HOSTED_SQLITE_DB_PATH = "/data/uptime/uptime.db";
|
|
828
|
+
var NFS_SUPER_MAGIC = 26985;
|
|
827
829
|
var SECRET_URL_PARAM_PATTERN = /(token|secret|password|passwd|api[_-]?key|access[_-]?token|auth|credential|session)/i;
|
|
828
830
|
var REQUIRED_TABLES = [
|
|
829
831
|
"schema_migrations",
|
|
@@ -860,18 +862,39 @@ class UptimeStore {
|
|
|
860
862
|
this.mode = resolveRuntimeMode(options.mode ?? "local");
|
|
861
863
|
const cloudDatabaseUrl = options.cloudDatabaseUrl ?? process.env.HASNA_UPTIME_DATABASE_URL;
|
|
862
864
|
if (this.mode === "hosted" && cloudDatabaseUrl) {
|
|
863
|
-
throw new Error("hosted
|
|
865
|
+
throw new Error("hosted Postgres adapter is not implemented yet; use HASNA_UPTIME_HOSTED_SQLITE_DB on cloud-mounted storage for the current hosted deployment path");
|
|
864
866
|
}
|
|
865
|
-
|
|
866
|
-
|
|
867
|
+
const hostedSqliteDbPath = options.hostedSqliteDbPath ?? process.env.HASNA_UPTIME_HOSTED_SQLITE_DB;
|
|
868
|
+
if (this.mode === "hosted" && hostedSqliteDbPath) {
|
|
869
|
+
if (hostedSqliteDbPath === ":memory:" || !hostedSqliteDbPath.startsWith("/")) {
|
|
870
|
+
throw new Error("HASNA_UPTIME_HOSTED_SQLITE_DB must be an absolute path on mounted cloud storage");
|
|
871
|
+
}
|
|
872
|
+
const approvedHostedPath = hostedSqliteDbPath === DEFAULT_HOSTED_SQLITE_DB_PATH;
|
|
873
|
+
if (!approvedHostedPath && !allowHostedLocalStore(options.allowHostedLocalStore)) {
|
|
874
|
+
throw new Error(`HASNA_UPTIME_HOSTED_SQLITE_DB must be ${DEFAULT_HOSTED_SQLITE_DB_PATH}; set HASNA_UPTIME_ALLOW_HOSTED_LOCAL_STORE=1 only for explicit local fallback testing`);
|
|
875
|
+
}
|
|
876
|
+
const verifiedCloudMount = approvedHostedPath && isNfsMount(dirname(hostedSqliteDbPath));
|
|
877
|
+
if (approvedHostedPath && !verifiedCloudMount && !allowHostedLocalStore(options.allowHostedLocalStore)) {
|
|
878
|
+
throw new Error(`${DEFAULT_HOSTED_SQLITE_DB_PATH} must be on a mounted EFS/NFS filesystem; refusing to create hosted task-local SQLite`);
|
|
879
|
+
}
|
|
880
|
+
this.dataMode = verifiedCloudMount ? "hosted-efs-sqlite" : "hosted-local-sqlite";
|
|
881
|
+
this.dbPath = hostedSqliteDbPath;
|
|
882
|
+
} else if (this.mode === "hosted") {
|
|
883
|
+
if (!allowHostedLocalStore(options.allowHostedLocalStore)) {
|
|
884
|
+
throw new Error("hosted mode requires HASNA_UPTIME_HOSTED_SQLITE_DB on mounted cloud storage; set HASNA_UPTIME_ALLOW_HOSTED_LOCAL_STORE=1 only for explicit local fallback testing");
|
|
885
|
+
}
|
|
886
|
+
this.dataMode = "hosted-local-sqlite";
|
|
887
|
+
this.dbPath = options.dbPath ?? uptimeHostedFallbackDbPath();
|
|
888
|
+
} else {
|
|
889
|
+
this.dataMode = "local-sqlite";
|
|
890
|
+
this.dbPath = options.dbPath ?? uptimeDbPath();
|
|
867
891
|
}
|
|
868
|
-
|
|
869
|
-
this.dbPath = options.dbPath ?? (this.mode === "hosted" ? uptimeHostedFallbackDbPath() : uptimeDbPath());
|
|
870
|
-
if (this.dbPath !== ":memory:") {
|
|
892
|
+
if (this.dbPath !== ":memory:" && this.dataMode !== "hosted-efs-sqlite") {
|
|
871
893
|
mkdirSync2(dirname(this.dbPath), { recursive: true });
|
|
872
894
|
}
|
|
873
895
|
this.db = new Database(this.dbPath, { create: true });
|
|
874
|
-
this.db.run("PRAGMA journal_mode = WAL");
|
|
896
|
+
this.db.run(this.dataMode === "hosted-efs-sqlite" ? "PRAGMA journal_mode = DELETE" : "PRAGMA journal_mode = WAL");
|
|
897
|
+
this.db.run("PRAGMA busy_timeout = 5000");
|
|
875
898
|
this.db.run("PRAGMA foreign_keys = ON");
|
|
876
899
|
this.migrate();
|
|
877
900
|
}
|
|
@@ -1751,6 +1774,13 @@ function resolveRuntimeMode(mode) {
|
|
|
1751
1774
|
function allowHostedLocalStore(value) {
|
|
1752
1775
|
return value === true || process.env.HASNA_UPTIME_ALLOW_HOSTED_LOCAL_STORE === "1";
|
|
1753
1776
|
}
|
|
1777
|
+
function isNfsMount(path) {
|
|
1778
|
+
try {
|
|
1779
|
+
return statfsSync(path).type === NFS_SUPER_MAGIC;
|
|
1780
|
+
} catch {
|
|
1781
|
+
return false;
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1754
1784
|
function verifyBackupFile(backupPath) {
|
|
1755
1785
|
const db = new Database(backupPath, { readonly: true });
|
|
1756
1786
|
try {
|
package/dist/store.d.ts
CHANGED
|
@@ -4,8 +4,10 @@ export interface UptimeStoreOptions {
|
|
|
4
4
|
mode?: UptimeRuntimeMode;
|
|
5
5
|
allowHostedLocalStore?: boolean;
|
|
6
6
|
cloudDatabaseUrl?: string;
|
|
7
|
+
hostedSqliteDbPath?: string;
|
|
7
8
|
}
|
|
8
9
|
export type UptimeRuntimeMode = "local" | "hosted";
|
|
10
|
+
export declare const DEFAULT_HOSTED_SQLITE_DB_PATH = "/data/uptime/uptime.db";
|
|
9
11
|
export interface UptimeBackup {
|
|
10
12
|
sourcePath: string;
|
|
11
13
|
backupPath: string;
|
|
@@ -56,7 +58,7 @@ export declare class StaleCheckResultError extends Error {
|
|
|
56
58
|
export declare class UptimeStore {
|
|
57
59
|
readonly dbPath: string;
|
|
58
60
|
readonly mode: UptimeRuntimeMode;
|
|
59
|
-
readonly dataMode: "local-sqlite" | "hosted-local-sqlite";
|
|
61
|
+
readonly dataMode: "local-sqlite" | "hosted-local-sqlite" | "hosted-efs-sqlite";
|
|
60
62
|
private readonly db;
|
|
61
63
|
constructor(options?: UptimeStoreOptions);
|
|
62
64
|
close(): void;
|
package/dist/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,UAAU,EAEV,WAAW,EACX,yBAAyB,EACzB,QAAQ,EACR,oBAAoB,EACpB,0BAA0B,EAC1B,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,OAAO,EAGP,aAAa,EAEb,aAAa,EACb,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,SAAS,EACT,eAAe,EACf,cAAc,EAEd,yBAAyB,EACzB,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,UAAU,EAEV,WAAW,EACX,yBAAyB,EACzB,QAAQ,EACR,oBAAoB,EACpB,0BAA0B,EAC1B,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,OAAO,EAGP,aAAa,EAEb,aAAa,EACb,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,SAAS,EACT,eAAe,EACf,cAAc,EAEd,yBAAyB,EACzB,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEnD,eAAO,MAAM,6BAA6B,2BAA2B,CAAC;AAKtE,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,aAAa,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,OAAO,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,EAAE,CAAC;CACpB;AAgLD,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,WAAW;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,cAAc,GAAG,qBAAqB,GAAG,mBAAmB,CAAC;IAChF,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAW;gBAElB,OAAO,GAAE,kBAAuB;IAyC5C,KAAK,IAAI,IAAI;IAIb,OAAO,IAAI,IAAI;IA2Lf,MAAM,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,YAAY;IAiB9C,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB;IAInD,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB;IAI1D,MAAM,CAAC,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,SAAiB,GAAG,YAAY;IAkBxF,aAAa,CAAC,KAAK,EAAE,oBAAoB,EAAE,OAAO,GAAE;QAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO;IAsDjG,YAAY,CAAC,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,EAAE;IAOpE,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IAO5C,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,0BAA0B,EAAE,OAAO,GAAE;QAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO;IA8CzH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAOxC,mBAAmB,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,oBAAoB,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,aAAa;IAiClI,mBAAmB,CAAC,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,aAAa,EAAE;IAOjF,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAOxD,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,aAAa;IAajG,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,SAA2B,GAAG,IAAI;IAM7E,mBAAmB,CAAC,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,aAAa;IAoDtG,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAKlD,kBAAkB,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,aAAa;IAwCjG,qBAAqB,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,aAAa;IA2BlJ,OAAO,CAAC,mBAAmB;IAM3B,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,sBAAsB,GAAG,IAAI;IAOjF,qBAAqB,CAAC,KAAK,EAAE,IAAI,CAAC,sBAAsB,EAAE,IAAI,GAAG,aAAa,CAAC,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,sBAAsB;IA+BnI,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,cAAc;IAqCtE,mBAAmB,CAAC,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,cAAc,EAAE;IAOlF,sBAAsB,CAAC,MAAM,SAA2B,GAAG,cAAc,EAAE;IAQ3E,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAO1D,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,yBAAyB,GAAG,cAAc;IAgCxF,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAO/C,eAAe,CAAC,KAAK,EAAE;QACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,MAAM,EAAE,eAAe,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,oBAAoB,EAAE,CAAC;QACpC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;KAC7C,GAAG,SAAS;IA4Cb,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,SAAS,EAAE;IAUhE,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,UAAU;IAiC1D,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,UAAU,EAAE;IAmBnE,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;IAmB3E,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAIzD,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,uBAAuB,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,WAAW;IA0DvI,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAK9C,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW,EAAE;IAU5D,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IAOzE,uBAAuB,CAAC,KAAK,EAAE,4BAA4B,GAAG,iBAAiB;IAwB/E,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,iBAAiB;IAQ/D,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IAOzD,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB;IAU7D,gBAAgB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC;IAInC,aAAa,CAAC,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,QAAQ,EAAE;IAmB3G,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAOnD,OAAO,IAAI,aAAa;IAkBxB,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,cAAc;IAyBtB,OAAO,CAAC,8BAA8B;IA4BtC,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,qBAAqB;IAc7B,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,kCAAkC;IAoD1C,OAAO,CAAC,UAAU;CAInB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,CAAC,EAAE,iBAAiB,GAAG,iBAAiB,CAI9E"}
|
package/dist/store.js
CHANGED
|
@@ -19,7 +19,7 @@ function ensureUptimeHome() {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
// src/store.ts
|
|
22
|
-
import { copyFileSync, existsSync, mkdirSync as mkdirSync2, statSync } from "fs";
|
|
22
|
+
import { copyFileSync, existsSync, mkdirSync as mkdirSync2, statfsSync, statSync } from "fs";
|
|
23
23
|
import { dirname, join as join2 } from "path";
|
|
24
24
|
import { randomUUID } from "crypto";
|
|
25
25
|
import { Database } from "bun:sqlite";
|
|
@@ -107,6 +107,8 @@ var MAX_RETRY_COUNT = 10;
|
|
|
107
107
|
var MAX_RESULT_LIMIT = 1000;
|
|
108
108
|
|
|
109
109
|
// src/store.ts
|
|
110
|
+
var DEFAULT_HOSTED_SQLITE_DB_PATH = "/data/uptime/uptime.db";
|
|
111
|
+
var NFS_SUPER_MAGIC = 26985;
|
|
110
112
|
var SECRET_URL_PARAM_PATTERN = /(token|secret|password|passwd|api[_-]?key|access[_-]?token|auth|credential|session)/i;
|
|
111
113
|
var REQUIRED_TABLES = [
|
|
112
114
|
"schema_migrations",
|
|
@@ -143,18 +145,39 @@ class UptimeStore {
|
|
|
143
145
|
this.mode = resolveRuntimeMode(options.mode ?? "local");
|
|
144
146
|
const cloudDatabaseUrl = options.cloudDatabaseUrl ?? process.env.HASNA_UPTIME_DATABASE_URL;
|
|
145
147
|
if (this.mode === "hosted" && cloudDatabaseUrl) {
|
|
146
|
-
throw new Error("hosted
|
|
148
|
+
throw new Error("hosted Postgres adapter is not implemented yet; use HASNA_UPTIME_HOSTED_SQLITE_DB on cloud-mounted storage for the current hosted deployment path");
|
|
147
149
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
+
const hostedSqliteDbPath = options.hostedSqliteDbPath ?? process.env.HASNA_UPTIME_HOSTED_SQLITE_DB;
|
|
151
|
+
if (this.mode === "hosted" && hostedSqliteDbPath) {
|
|
152
|
+
if (hostedSqliteDbPath === ":memory:" || !hostedSqliteDbPath.startsWith("/")) {
|
|
153
|
+
throw new Error("HASNA_UPTIME_HOSTED_SQLITE_DB must be an absolute path on mounted cloud storage");
|
|
154
|
+
}
|
|
155
|
+
const approvedHostedPath = hostedSqliteDbPath === DEFAULT_HOSTED_SQLITE_DB_PATH;
|
|
156
|
+
if (!approvedHostedPath && !allowHostedLocalStore(options.allowHostedLocalStore)) {
|
|
157
|
+
throw new Error(`HASNA_UPTIME_HOSTED_SQLITE_DB must be ${DEFAULT_HOSTED_SQLITE_DB_PATH}; set HASNA_UPTIME_ALLOW_HOSTED_LOCAL_STORE=1 only for explicit local fallback testing`);
|
|
158
|
+
}
|
|
159
|
+
const verifiedCloudMount = approvedHostedPath && isNfsMount(dirname(hostedSqliteDbPath));
|
|
160
|
+
if (approvedHostedPath && !verifiedCloudMount && !allowHostedLocalStore(options.allowHostedLocalStore)) {
|
|
161
|
+
throw new Error(`${DEFAULT_HOSTED_SQLITE_DB_PATH} must be on a mounted EFS/NFS filesystem; refusing to create hosted task-local SQLite`);
|
|
162
|
+
}
|
|
163
|
+
this.dataMode = verifiedCloudMount ? "hosted-efs-sqlite" : "hosted-local-sqlite";
|
|
164
|
+
this.dbPath = hostedSqliteDbPath;
|
|
165
|
+
} else if (this.mode === "hosted") {
|
|
166
|
+
if (!allowHostedLocalStore(options.allowHostedLocalStore)) {
|
|
167
|
+
throw new Error("hosted mode requires HASNA_UPTIME_HOSTED_SQLITE_DB on mounted cloud storage; set HASNA_UPTIME_ALLOW_HOSTED_LOCAL_STORE=1 only for explicit local fallback testing");
|
|
168
|
+
}
|
|
169
|
+
this.dataMode = "hosted-local-sqlite";
|
|
170
|
+
this.dbPath = options.dbPath ?? uptimeHostedFallbackDbPath();
|
|
171
|
+
} else {
|
|
172
|
+
this.dataMode = "local-sqlite";
|
|
173
|
+
this.dbPath = options.dbPath ?? uptimeDbPath();
|
|
150
174
|
}
|
|
151
|
-
|
|
152
|
-
this.dbPath = options.dbPath ?? (this.mode === "hosted" ? uptimeHostedFallbackDbPath() : uptimeDbPath());
|
|
153
|
-
if (this.dbPath !== ":memory:") {
|
|
175
|
+
if (this.dbPath !== ":memory:" && this.dataMode !== "hosted-efs-sqlite") {
|
|
154
176
|
mkdirSync2(dirname(this.dbPath), { recursive: true });
|
|
155
177
|
}
|
|
156
178
|
this.db = new Database(this.dbPath, { create: true });
|
|
157
|
-
this.db.run("PRAGMA journal_mode = WAL");
|
|
179
|
+
this.db.run(this.dataMode === "hosted-efs-sqlite" ? "PRAGMA journal_mode = DELETE" : "PRAGMA journal_mode = WAL");
|
|
180
|
+
this.db.run("PRAGMA busy_timeout = 5000");
|
|
158
181
|
this.db.run("PRAGMA foreign_keys = ON");
|
|
159
182
|
this.migrate();
|
|
160
183
|
}
|
|
@@ -1034,6 +1057,13 @@ function resolveRuntimeMode(mode) {
|
|
|
1034
1057
|
function allowHostedLocalStore(value) {
|
|
1035
1058
|
return value === true || process.env.HASNA_UPTIME_ALLOW_HOSTED_LOCAL_STORE === "1";
|
|
1036
1059
|
}
|
|
1060
|
+
function isNfsMount(path) {
|
|
1061
|
+
try {
|
|
1062
|
+
return statfsSync(path).type === NFS_SUPER_MAGIC;
|
|
1063
|
+
} catch {
|
|
1064
|
+
return false;
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1037
1067
|
function verifyBackupFile(backupPath) {
|
|
1038
1068
|
const db = new Database(backupPath, { readonly: true });
|
|
1039
1069
|
try {
|
|
@@ -1581,5 +1611,6 @@ function round(value, places) {
|
|
|
1581
1611
|
export {
|
|
1582
1612
|
resolveRuntimeMode,
|
|
1583
1613
|
UptimeStore,
|
|
1584
|
-
StaleCheckResultError
|
|
1614
|
+
StaleCheckResultError,
|
|
1615
|
+
DEFAULT_HOSTED_SQLITE_DB_PATH
|
|
1585
1616
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# AWS Deployment Runbook
|
|
2
2
|
|
|
3
|
-
This runbook is for
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
This runbook is for a reviewed AWS account target. It is intentionally dry-run
|
|
4
|
+
first: the local generator produces a plan and command list, but it does not
|
|
5
|
+
call AWS or mutate infrastructure.
|
|
6
6
|
|
|
7
7
|
## Generate The Plan
|
|
8
8
|
|
|
@@ -11,16 +11,18 @@ uptime cloud plan --json > open-uptime-aws-plan.json
|
|
|
11
11
|
uptime cloud spark01-config --probe-id prb_spark01 --env > spark01-uptime.env
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Public package defaults are placeholders:
|
|
15
15
|
|
|
16
|
-
- account/profile label: `
|
|
16
|
+
- account/profile label: `aws-profile`
|
|
17
17
|
- region: `us-east-1`
|
|
18
|
-
- VPC: `vpc-
|
|
19
|
-
-
|
|
20
|
-
- hostname: `uptime.
|
|
21
|
-
- workspace id: `
|
|
18
|
+
- VPC: `vpc-xxxxxxxx`
|
|
19
|
+
- hosted data path: EFS-mounted SQLite at `/data/uptime/uptime.db`
|
|
20
|
+
- hostname: `uptime.example.com`
|
|
21
|
+
- workspace id: `workspace-id`
|
|
22
|
+
- protected access mode: `cloudfront_default_domain`
|
|
22
23
|
|
|
23
|
-
Override these with CLI flags
|
|
24
|
+
Override these with CLI flags or private deployment evidence for the real
|
|
25
|
+
account, hostname, workspace id, VPC id, secret refs, and repository names.
|
|
24
26
|
|
|
25
27
|
The generated AWS plan currently returns `status: "blocked"` and
|
|
26
28
|
`canApply: false`. The generated Spark01 config returns `status: "blocked"` and
|
|
@@ -36,16 +38,19 @@ write a sourceable env file with a placeholder probe identity.
|
|
|
36
38
|
|
|
37
39
|
## Preflight
|
|
38
40
|
|
|
39
|
-
1. Locate the real
|
|
40
|
-
|
|
41
|
+
1. Locate the real infrastructure repository or create the change in the
|
|
42
|
+
approved owner repository.
|
|
41
43
|
2. Confirm the AWS caller identity:
|
|
42
44
|
|
|
43
45
|
```bash
|
|
44
|
-
aws sts get-caller-identity --profile
|
|
46
|
+
aws sts get-caller-identity --profile <aws-profile>
|
|
45
47
|
```
|
|
46
48
|
|
|
47
|
-
3. Confirm the target VPC
|
|
48
|
-
|
|
49
|
+
3. Confirm the target VPC, private subnets, KMS key, and EFS/Backup plan inputs
|
|
50
|
+
still match the plan.
|
|
51
|
+
4. Confirm the protected access mode. The first deploy can use the CloudFront
|
|
52
|
+
default HTTPS domain without custom DNS or ACM. Custom hostname deploys still
|
|
53
|
+
require Route53/edge ownership and an ACM certificate.
|
|
49
54
|
5. Confirm the deployment role uses short-lived credentials or OIDC, not copied
|
|
50
55
|
access keys.
|
|
51
56
|
|
|
@@ -55,11 +60,15 @@ The plan expects:
|
|
|
55
60
|
|
|
56
61
|
- ECR repository for the Open Uptime image.
|
|
57
62
|
- ECS/Fargate cluster with separate services for web, scheduler, public probe,
|
|
58
|
-
reporter, and one-off migrations.
|
|
59
|
-
|
|
60
|
-
-
|
|
63
|
+
reporter, and one-off migrations. In the current EFS SQLite bridge, only web
|
|
64
|
+
may be enabled and it must run at desired count `0` or `1`.
|
|
65
|
+
- CloudFront default-domain HTTPS edge plus ALB HTTP origin restricted to
|
|
66
|
+
CloudFront origin-facing ranges, or an ALB HTTPS listener with ACM certificate
|
|
67
|
+
when custom DNS is approved.
|
|
68
|
+
- Encrypted EFS file system, access point, mount targets, and AWS Backup plan
|
|
69
|
+
for `HASNA_UPTIME_HOSTED_SQLITE_DB=/data/uptime/uptime.db`.
|
|
61
70
|
- S3 bucket for redacted browser evidence and generated report artifacts.
|
|
62
|
-
- Secrets Manager or SSM refs for
|
|
71
|
+
- Secrets Manager or SSM refs for app env, hosted token, probe config, and
|
|
63
72
|
reporting channel refs.
|
|
64
73
|
- CloudWatch log groups for every component plus initial web 5xx/unhealthy
|
|
65
74
|
alarms. Scheduler-stall, stale-probe, and report-delivery alarms remain
|
|
@@ -78,6 +87,8 @@ terraform -chdir=infra/aws validate
|
|
|
78
87
|
terraform -chdir=infra/aws plan -out open-uptime.tfplan
|
|
79
88
|
```
|
|
80
89
|
|
|
90
|
+
Use Terraform/OpenTofu 1.9 or newer for this starter.
|
|
91
|
+
|
|
81
92
|
## Spark01
|
|
82
93
|
|
|
83
94
|
Spark01 should be a private probe/operator machine, not the hosted source of
|
|
@@ -91,11 +102,21 @@ routes are backed by cloud check jobs and cloud audit rows.
|
|
|
91
102
|
## Safety Rules
|
|
92
103
|
|
|
93
104
|
- Do not deploy hosted mode with `HASNA_UPTIME_ALLOW_HOSTED_LOCAL_STORE=1`.
|
|
105
|
+
- Do deploy hosted mode with `HASNA_UPTIME_HOSTED_SQLITE_DB` pointing at the EFS
|
|
106
|
+
mount path `/data/uptime/uptime.db`. Do not set `HASNA_UPTIME_DATABASE_URL`
|
|
107
|
+
until the async Postgres adapter exists.
|
|
108
|
+
- Do set `HASNA_UPTIME_ALLOWED_ORIGINS` on the hosted web task to the public
|
|
109
|
+
HTTPS edge origin, such as the CloudFront default domain or approved custom
|
|
110
|
+
hostname.
|
|
94
111
|
- Do not inline AWS keys, hosted tokens, Mailery keys, Open Logs tokens, database
|
|
95
112
|
URLs, or probe private keys in task definitions. Use ECS `secrets.valueFrom`
|
|
96
|
-
refs such as `
|
|
113
|
+
refs such as `HASNA_UPTIME_HOSTED_TOKEN`.
|
|
97
114
|
- Do not run public probe workers against private targets.
|
|
115
|
+
- Do not enable scheduler, public-probe, reporter, or migration workers against
|
|
116
|
+
the EFS SQLite bridge; those services need Postgres/cloud leases first.
|
|
98
117
|
- Do not expose dashboard/API routes without hosted auth and workspace checks.
|
|
118
|
+
- Do not expose the ALB directly in CloudFront mode; ALB ingress must be limited
|
|
119
|
+
to CloudFront origin-facing ranges.
|
|
99
120
|
- Do not treat local SQLite, local project DBs, or Spark01 local state as cloud
|
|
100
121
|
authority after cutover.
|
|
101
122
|
|
|
@@ -103,5 +124,6 @@ routes are backed by cloud check jobs and cloud audit rows.
|
|
|
103
124
|
|
|
104
125
|
Before each service update, record the previous task definition ARN. Roll back
|
|
105
126
|
by disabling scheduler/reporter work first, then restoring the previous web or
|
|
106
|
-
worker task definition.
|
|
107
|
-
|
|
127
|
+
worker task definition. EFS backup restore requires separate operator approval,
|
|
128
|
+
a selected recovery point, a replacement mount target/access point cutover, and
|
|
129
|
+
an audit event.
|
package/infra/aws/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Open Uptime AWS Infra
|
|
2
2
|
|
|
3
3
|
This directory is a reviewable Terraform/OpenTofu starting point for deploying
|
|
4
|
-
Open Uptime in
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
Open Uptime in a reviewed AWS account. It is intentionally plan-first. Do not
|
|
5
|
+
apply it directly from this app repo unless the infrastructure owner has
|
|
6
|
+
approved this directory as the source of truth or has copied it into the
|
|
7
|
+
approved infra repository.
|
|
8
8
|
|
|
9
9
|
## Expected Flow
|
|
10
10
|
|
|
@@ -15,18 +15,39 @@ terraform -chdir=infra/aws validate
|
|
|
15
15
|
terraform -chdir=infra/aws plan -out open-uptime.tfplan
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
Terraform 1.9 or newer is required by the variable validation in this starter.
|
|
19
|
+
|
|
18
20
|
Required inputs are declared in `variables.tf` and illustrated in
|
|
19
21
|
`terraform.tfvars.example`. Secrets are passed as Secrets Manager/SSM ARNs only;
|
|
20
22
|
never place plaintext tokens, database URLs, private keys, or channel
|
|
21
23
|
credentials in `.tfvars` files.
|
|
22
24
|
|
|
25
|
+
The current deployable hosted state path is EFS-backed SQLite mounted at
|
|
26
|
+
`/data/uptime/uptime.db` and wired through `HASNA_UPTIME_HOSTED_SQLITE_DB` for
|
|
27
|
+
one protected web task maximum. Scheduler, public-probe, reporter, and migration
|
|
28
|
+
must remain at desired count `0` and receive no EFS mount until the Postgres
|
|
29
|
+
adapter and cloud leases are implemented. Do not set
|
|
30
|
+
`HASNA_UPTIME_DATABASE_URL` for hosted ECS tasks until then.
|
|
31
|
+
|
|
32
|
+
The included CodeBuild project builds `@hasna/uptime` from npm with
|
|
33
|
+
`Dockerfile.package` and pushes the resulting image to ECR. This avoids
|
|
34
|
+
depending on a local Docker daemon for image publication.
|
|
35
|
+
|
|
36
|
+
The default protected access mode is `cloudfront_default_domain`: CloudFront
|
|
37
|
+
serves HTTPS on its default domain while the ALB origin accepts HTTP only from
|
|
38
|
+
AWS's CloudFront origin-facing managed prefix list. Use `alb_https_cert` only
|
|
39
|
+
after custom DNS and an ACM certificate are approved.
|
|
40
|
+
The web task receives `HASNA_UPTIME_ALLOWED_ORIGINS` for the selected public
|
|
41
|
+
HTTPS origin so hosted mutation CSRF checks still work through the private HTTP
|
|
42
|
+
origin hop.
|
|
43
|
+
|
|
23
44
|
## Current Blockers
|
|
24
45
|
|
|
25
|
-
- Hosted Postgres adapter and migrations are not implemented in the app yet.
|
|
26
46
|
- Hosted production auth/RBAC still needs scoped, revocable credentials.
|
|
27
47
|
- Public probe runtime still needs execution-time DNS/redirect/rebinding SSRF
|
|
28
48
|
enforcement.
|
|
29
49
|
- Spark01 hosted private-probe enrollment/heartbeat/revocation is still
|
|
30
50
|
fail-closed.
|
|
31
51
|
|
|
32
|
-
Keep `desired_count` at `0
|
|
52
|
+
Keep `desired_count` at `0`, or at `1` for the protected web bridge only after
|
|
53
|
+
review evidence exists, until those blockers are closed.
|