diff --git a/Dockerfile b/Dockerfile index 9cd95d9..87b42b1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,7 +37,7 @@ RUN APKO_ARCH=$([ "$TARGETARCH" = "arm64" ] && echo "aarch64" || echo "x86_64") " - busybox" \ " - tzdata" \ " - docker-cli" \ - " - docker-compose=5.1.4-r4" \ + " - docker-compose=5.1.4-r5" \ " - docker-cli-buildx" \ " - sqlite" \ " - postgresql-client" \ diff --git a/VERSION b/VERSION index d11e881..77f359c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v1.0.32 +v1.0.33 diff --git a/collector/main.go b/collector/main.go index 7f5bd8d..cd96736 100644 --- a/collector/main.go +++ b/collector/main.go @@ -221,13 +221,19 @@ func buildClients(cfg *EnvConfig) (client *http.Client, streamClient *http.Clien baseURL = "http://localhost" case "http": + // Explicit dial timeout and TCP keepalive so connections over dead + // tunnels (VPN/Tailscale drops) are detected at kernel level instead + // of hanging indefinitely. + tcpDial := (&net.Dialer{Timeout: 10 * time.Second, KeepAlive: 15 * time.Second}).DialContext transport = &http.Transport{ + DialContext: tcpDial, MaxIdleConns: 16, MaxIdleConnsPerHost: 16, MaxConnsPerHost: 16, IdleConnTimeout: 90 * time.Second, } streamTransport = &http.Transport{ + DialContext: tcpDial, MaxIdleConns: 4, MaxIdleConnsPerHost: 4, MaxConnsPerHost: 4, @@ -242,7 +248,9 @@ func buildClients(cfg *EnvConfig) (client *http.Client, streamClient *http.Clien } streamTLSCfg := tlsCfg.Clone() + tcpDial := (&net.Dialer{Timeout: 10 * time.Second, KeepAlive: 15 * time.Second}).DialContext transport = &http.Transport{ + DialContext: tcpDial, TLSClientConfig: tlsCfg, MaxIdleConns: 16, MaxIdleConnsPerHost: 16, @@ -250,6 +258,7 @@ func buildClients(cfg *EnvConfig) (client *http.Client, streamClient *http.Clien IdleConnTimeout: 90 * time.Second, } streamTransport = &http.Transport{ + DialContext: tcpDial, TLSClientConfig: streamTLSCfg, MaxIdleConns: 4, MaxIdleConnsPerHost: 4, @@ -322,15 +331,32 @@ func (e *environment) doStreamRequest(ctx context.Context, method, path string) return e.streamClient.Do(req) } -func (e *environment) ping(ctx context.Context) bool { - ctx, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() - resp, err := e.doRequest(ctx, "GET", "/_ping") - if err != nil { - return false +func (e *environment) ping(ctx context.Context) error { + attempt := func() error { + pingCtx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + resp, err := e.doRequest(pingCtx, "GET", "/_ping") + if err != nil { + return err + } + drainAndClose(resp) + if resp.StatusCode != 200 { + return fmt.Errorf("ping returned status %d", resp.StatusCode) + } + return nil } - drainAndClose(resp) - return resp.StatusCode == 200 + + if err := attempt(); err == nil { + return nil + } else if ctx.Err() != nil { + return err + } + + // Stale pooled connections (e.g. after a VPN/tunnel drop) hang requests + // until timeout while the host is actually reachable. Evict the pool and + // retry once on a guaranteed-fresh connection. + e.closeTransports() + return attempt() } // --------------------------------------------------------------------------- @@ -358,11 +384,11 @@ func (m *manager) runMetrics(env *environment) { } func (m *manager) collectMetrics(env *environment) { - if !env.ping(env.ctx) { + if err := env.ping(env.ctx); err != nil { if env.online || !env.statusReported { env.online = false env.statusReported = true - m.send(OutMessage{Type: "env_status", EnvID: env.id, Online: boolPtr(false), Error: "Docker not reachable"}) + m.send(OutMessage{Type: "env_status", EnvID: env.id, Online: boolPtr(false), Error: "Docker not reachable: " + err.Error()}) } return } @@ -558,11 +584,11 @@ func (m *manager) runEvents(env *environment) { } // Stream mode - if !env.ping(env.ctx) { + if err := env.ping(env.ctx); err != nil { if env.online || !env.statusReported { env.online = false env.statusReported = true - m.send(OutMessage{Type: "env_status", EnvID: env.id, Online: boolPtr(false), Error: "Docker not reachable"}) + m.send(OutMessage{Type: "env_status", EnvID: env.id, Online: boolPtr(false), Error: "Docker not reachable: " + err.Error()}) } if !waitOrCancel(reconnectDelay) { return @@ -609,12 +635,32 @@ func (m *manager) runEvents(env *environment) { // Force-close the body on context cancellation so scanner.Scan() // unblocks. Without this, the goroutine can leak if the transport's // internal cancel watcher doesn't fire (Go runtime implementation detail). + // + // The watchdog ticker handles half-open connections (e.g. after a + // VPN/tunnel drop): the stream client has no timeout, so Scan() would + // otherwise block forever on a dead connection that never errors. + // A failed ping (which retries on a fresh connection internally) + // means the host is unreachable — close the body so the reconnect + // loop takes over. bodyDone := make(chan struct{}) + var closeBodyOnce sync.Once + closeBody := func() { closeBodyOnce.Do(func() { resp.Body.Close() }) } go func() { - select { - case <-env.ctx.Done(): - resp.Body.Close() - case <-bodyDone: + watchdog := time.NewTicker(90 * time.Second) + defer watchdog.Stop() + for { + select { + case <-env.ctx.Done(): + closeBody() + return + case <-bodyDone: + return + case <-watchdog.C: + if env.ping(env.ctx) != nil { + closeBody() + return + } + } } }() @@ -638,7 +684,7 @@ func (m *manager) runEvents(env *environment) { } } close(bodyDone) - resp.Body.Close() + closeBody() if env.ctx.Err() != nil { return @@ -653,11 +699,11 @@ func (m *manager) runEvents(env *environment) { } func (m *manager) pollEvents(env *environment) { - if !env.ping(env.ctx) { + if err := env.ping(env.ctx); err != nil { if env.online || !env.statusReported { env.online = false env.statusReported = true - m.send(OutMessage{Type: "env_status", EnvID: env.id, Online: boolPtr(false), Error: "Docker not reachable"}) + m.send(OutMessage{Type: "env_status", EnvID: env.id, Online: boolPtr(false), Error: "Docker not reachable: " + err.Error()}) } return } @@ -736,7 +782,7 @@ func (m *manager) runDiskChecks(env *environment) { } func (m *manager) checkDisk(env *environment) { - if !env.ping(env.ctx) { + if env.ping(env.ctx) != nil { return } diff --git a/drizzle-pg/0007_add_synced_files.sql b/drizzle-pg/0007_add_synced_files.sql new file mode 100644 index 0000000..c210acd --- /dev/null +++ b/drizzle-pg/0007_add_synced_files.sql @@ -0,0 +1 @@ +ALTER TABLE "git_stacks" ADD COLUMN "synced_files" text; \ No newline at end of file diff --git a/drizzle-pg/meta/0007_snapshot.json b/drizzle-pg/meta/0007_snapshot.json new file mode 100644 index 0000000..cc75484 --- /dev/null +++ b/drizzle-pg/meta/0007_snapshot.json @@ -0,0 +1,3057 @@ +{ + "id": "dff63f66-aab4-4520-af39-5d2a4d7ba9ef", + "prevId": "0006_add_git_stack_context_dir", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.api_tokens": { + "name": "api_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_prefix": { + "name": "token_prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_used": { + "name": "last_used", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "api_tokens_user_id_idx": { + "name": "api_tokens_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "api_tokens_token_prefix_idx": { + "name": "api_tokens_token_prefix_idx", + "columns": [ + { + "expression": "token_prefix", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "api_tokens_user_id_users_id_fk": { + "name": "api_tokens_user_id_users_id_fk", + "tableFrom": "api_tokens", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_tokens_token_hash_unique": { + "name": "api_tokens_token_hash_unique", + "nullsNotDistinct": false, + "columns": [ + "token_hash" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_logs": { + "name": "audit_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_type": { + "name": "entity_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "entity_name": { + "name": "entity_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "details": { + "name": "details", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "audit_logs_user_id_idx": { + "name": "audit_logs_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_logs_created_at_idx": { + "name": "audit_logs_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audit_logs_user_id_users_id_fk": { + "name": "audit_logs_user_id_users_id_fk", + "tableFrom": "audit_logs", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "audit_logs_environment_id_environments_id_fk": { + "name": "audit_logs_environment_id_environments_id_fk", + "tableFrom": "audit_logs", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth_settings": { + "name": "auth_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "auth_enabled": { + "name": "auth_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "default_provider": { + "name": "default_provider", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'local'" + }, + "session_timeout": { + "name": "session_timeout", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 86400 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auto_update_settings": { + "name": "auto_update_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "container_name": { + "name": "container_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "schedule_type": { + "name": "schedule_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'daily'" + }, + "cron_expression": { + "name": "cron_expression", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "vulnerability_criteria": { + "name": "vulnerability_criteria", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'never'" + }, + "last_checked": { + "name": "last_checked", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_updated": { + "name": "last_updated", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "auto_update_settings_environment_id_environments_id_fk": { + "name": "auto_update_settings_environment_id_environments_id_fk", + "tableFrom": "auto_update_settings", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "auto_update_settings_environment_id_container_name_unique": { + "name": "auto_update_settings_environment_id_container_name_unique", + "nullsNotDistinct": false, + "columns": [ + "environment_id", + "container_name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.config_sets": { + "name": "config_sets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env_vars": { + "name": "env_vars", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "labels": { + "name": "labels", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ports": { + "name": "ports", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumes": { + "name": "volumes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "network_mode": { + "name": "network_mode", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'bridge'" + }, + "restart_policy": { + "name": "restart_policy", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'no'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "config_sets_name_unique": { + "name": "config_sets_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.container_events": { + "name": "container_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "container_id": { + "name": "container_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "container_name": { + "name": "container_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "actor_attributes": { + "name": "actor_attributes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "container_events_env_timestamp_idx": { + "name": "container_events_env_timestamp_idx", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "timestamp", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "container_events_environment_id_environments_id_fk": { + "name": "container_events_environment_id_environments_id_fk", + "tableFrom": "container_events", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.environment_notifications": { + "name": "environment_notifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "notification_id": { + "name": "notification_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "event_types": { + "name": "event_types", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "environment_notifications_environment_id_environments_id_fk": { + "name": "environment_notifications_environment_id_environments_id_fk", + "tableFrom": "environment_notifications", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "environment_notifications_notification_id_notification_settings_id_fk": { + "name": "environment_notifications_notification_id_notification_settings_id_fk", + "tableFrom": "environment_notifications", + "tableTo": "notification_settings", + "columnsFrom": [ + "notification_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "environment_notifications_environment_id_notification_id_unique": { + "name": "environment_notifications_environment_id_notification_id_unique", + "nullsNotDistinct": false, + "columns": [ + "environment_id", + "notification_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.environments": { + "name": "environments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 2375 + }, + "protocol": { + "name": "protocol", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'http'" + }, + "tls_ca": { + "name": "tls_ca", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tls_cert": { + "name": "tls_cert", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tls_key": { + "name": "tls_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tls_skip_verify": { + "name": "tls_skip_verify", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'globe'" + }, + "collect_activity": { + "name": "collect_activity", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "collect_metrics": { + "name": "collect_metrics", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "highlight_changes": { + "name": "highlight_changes", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "labels": { + "name": "labels", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "connection_type": { + "name": "connection_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'socket'" + }, + "socket_path": { + "name": "socket_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/var/run/docker.sock'" + }, + "hawser_token": { + "name": "hawser_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hawser_last_seen": { + "name": "hawser_last_seen", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "hawser_agent_id": { + "name": "hawser_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hawser_agent_name": { + "name": "hawser_agent_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hawser_version": { + "name": "hawser_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hawser_capabilities": { + "name": "hawser_capabilities", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "environments_name_unique": { + "name": "environments_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.git_credentials": { + "name": "git_credentials", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ssh_private_key": { + "name": "ssh_private_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ssh_passphrase": { + "name": "ssh_passphrase", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "git_credentials_name_unique": { + "name": "git_credentials_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.git_repositories": { + "name": "git_repositories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'main'" + }, + "credential_id": { + "name": "credential_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "compose_path": { + "name": "compose_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'docker-compose.yml'" + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "auto_update": { + "name": "auto_update", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "auto_update_schedule": { + "name": "auto_update_schedule", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'daily'" + }, + "auto_update_cron": { + "name": "auto_update_cron", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'0 3 * * *'" + }, + "webhook_enabled": { + "name": "webhook_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "webhook_secret": { + "name": "webhook_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_sync": { + "name": "last_sync", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_commit": { + "name": "last_commit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sync_status": { + "name": "sync_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'pending'" + }, + "sync_error": { + "name": "sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "git_repositories_credential_id_git_credentials_id_fk": { + "name": "git_repositories_credential_id_git_credentials_id_fk", + "tableFrom": "git_repositories", + "tableTo": "git_credentials", + "columnsFrom": [ + "credential_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "git_repositories_name_unique": { + "name": "git_repositories_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.git_stacks": { + "name": "git_stacks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "stack_name": { + "name": "stack_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "repository_id": { + "name": "repository_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "compose_path": { + "name": "compose_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'docker-compose.yml'" + }, + "env_file_path": { + "name": "env_file_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "auto_update": { + "name": "auto_update", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "auto_update_schedule": { + "name": "auto_update_schedule", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'daily'" + }, + "auto_update_cron": { + "name": "auto_update_cron", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'0 3 * * *'" + }, + "webhook_enabled": { + "name": "webhook_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "webhook_secret": { + "name": "webhook_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "context_dir": { + "name": "context_dir", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "build_on_deploy": { + "name": "build_on_deploy", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "no_build_cache": { + "name": "no_build_cache", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "repull_images": { + "name": "repull_images", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "force_redeploy": { + "name": "force_redeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "last_sync": { + "name": "last_sync", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_commit": { + "name": "last_commit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sync_status": { + "name": "sync_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'pending'" + }, + "sync_error": { + "name": "sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "synced_files": { + "name": "synced_files", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "git_stacks_environment_id_environments_id_fk": { + "name": "git_stacks_environment_id_environments_id_fk", + "tableFrom": "git_stacks", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "git_stacks_repository_id_git_repositories_id_fk": { + "name": "git_stacks_repository_id_git_repositories_id_fk", + "tableFrom": "git_stacks", + "tableTo": "git_repositories", + "columnsFrom": [ + "repository_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "git_stacks_stack_name_environment_id_unique": { + "name": "git_stacks_stack_name_environment_id_unique", + "nullsNotDistinct": false, + "columns": [ + "stack_name", + "environment_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hawser_tokens": { + "name": "hawser_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_prefix": { + "name": "token_prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "last_used": { + "name": "last_used", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "hawser_tokens_environment_id_environments_id_fk": { + "name": "hawser_tokens_environment_id_environments_id_fk", + "tableFrom": "hawser_tokens", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "hawser_tokens_token_unique": { + "name": "hawser_tokens_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.host_metrics": { + "name": "host_metrics", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cpu_percent": { + "name": "cpu_percent", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "memory_percent": { + "name": "memory_percent", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "memory_used": { + "name": "memory_used", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "memory_total": { + "name": "memory_total", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "host_metrics_env_timestamp_idx": { + "name": "host_metrics_env_timestamp_idx", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "timestamp", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "host_metrics_environment_id_environments_id_fk": { + "name": "host_metrics_environment_id_environments_id_fk", + "tableFrom": "host_metrics", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ldap_config": { + "name": "ldap_config", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "server_url": { + "name": "server_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bind_dn": { + "name": "bind_dn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bind_password": { + "name": "bind_password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "base_dn": { + "name": "base_dn", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_filter": { + "name": "user_filter", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'(uid={{username}})'" + }, + "username_attribute": { + "name": "username_attribute", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'uid'" + }, + "email_attribute": { + "name": "email_attribute", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'mail'" + }, + "display_name_attribute": { + "name": "display_name_attribute", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'cn'" + }, + "group_base_dn": { + "name": "group_base_dn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "group_filter": { + "name": "group_filter", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "admin_group": { + "name": "admin_group", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role_mappings": { + "name": "role_mappings", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tls_enabled": { + "name": "tls_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "tls_ca": { + "name": "tls_ca", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notification_settings": { + "name": "notification_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "config": { + "name": "config", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event_types": { + "name": "event_types", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.oidc_config": { + "name": "oidc_config", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "issuer_url": { + "name": "issuer_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "client_secret": { + "name": "client_secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "redirect_uri": { + "name": "redirect_uri", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'openid profile email'" + }, + "username_claim": { + "name": "username_claim", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'preferred_username'" + }, + "email_claim": { + "name": "email_claim", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'email'" + }, + "display_name_claim": { + "name": "display_name_claim", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'name'" + }, + "admin_claim": { + "name": "admin_claim", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "admin_value": { + "name": "admin_value", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role_mappings_claim": { + "name": "role_mappings_claim", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'groups'" + }, + "role_mappings": { + "name": "role_mappings", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pending_container_updates": { + "name": "pending_container_updates", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "container_id": { + "name": "container_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "container_name": { + "name": "container_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "current_image": { + "name": "current_image", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "checked_at": { + "name": "checked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "pending_container_updates_environment_id_environments_id_fk": { + "name": "pending_container_updates_environment_id_environments_id_fk", + "tableFrom": "pending_container_updates", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "pending_container_updates_environment_id_container_id_unique": { + "name": "pending_container_updates_environment_id_container_id_unique", + "nullsNotDistinct": false, + "columns": [ + "environment_id", + "container_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registries": { + "name": "registries", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "registries_name_unique": { + "name": "registries_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.roles": { + "name": "roles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_system": { + "name": "is_system", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "permissions": { + "name": "permissions", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environment_ids": { + "name": "environment_ids", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "roles_name_unique": { + "name": "roles_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.schedule_executions": { + "name": "schedule_executions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "schedule_type": { + "name": "schedule_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "schedule_id": { + "name": "schedule_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "entity_name": { + "name": "entity_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "triggered_by": { + "name": "triggered_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "triggered_at": { + "name": "triggered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "duration": { + "name": "duration", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "details": { + "name": "details", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "logs": { + "name": "logs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "schedule_executions_type_id_idx": { + "name": "schedule_executions_type_id_idx", + "columns": [ + { + "expression": "schedule_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "schedule_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "schedule_executions_environment_id_environments_id_fk": { + "name": "schedule_executions_environment_id_environments_id_fk", + "tableFrom": "schedule_executions", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sessions": { + "name": "sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "sessions_user_id_idx": { + "name": "sessions_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sessions_expires_at_idx": { + "name": "sessions_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "sessions_user_id_users_id_fk": { + "name": "sessions_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.settings": { + "name": "settings", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.stack_environment_variables": { + "name": "stack_environment_variables", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "stack_name": { + "name": "stack_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_secret": { + "name": "is_secret", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "stack_environment_variables_environment_id_environments_id_fk": { + "name": "stack_environment_variables_environment_id_environments_id_fk", + "tableFrom": "stack_environment_variables", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "stack_environment_variables_stack_name_environment_id_key_unique": { + "name": "stack_environment_variables_stack_name_environment_id_key_unique", + "nullsNotDistinct": false, + "columns": [ + "stack_name", + "environment_id", + "key" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.stack_events": { + "name": "stack_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "stack_name": { + "name": "stack_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "stack_events_environment_id_environments_id_fk": { + "name": "stack_events_environment_id_environments_id_fk", + "tableFrom": "stack_events", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.stack_sources": { + "name": "stack_sources", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "stack_name": { + "name": "stack_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'internal'" + }, + "git_repository_id": { + "name": "git_repository_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "git_stack_id": { + "name": "git_stack_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "compose_path": { + "name": "compose_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env_path": { + "name": "env_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "stack_sources_environment_id_environments_id_fk": { + "name": "stack_sources_environment_id_environments_id_fk", + "tableFrom": "stack_sources", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "stack_sources_git_repository_id_git_repositories_id_fk": { + "name": "stack_sources_git_repository_id_git_repositories_id_fk", + "tableFrom": "stack_sources", + "tableTo": "git_repositories", + "columnsFrom": [ + "git_repository_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "stack_sources_git_stack_id_git_stacks_id_fk": { + "name": "stack_sources_git_stack_id_git_stacks_id_fk", + "tableFrom": "stack_sources", + "tableTo": "git_stacks", + "columnsFrom": [ + "git_stack_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "stack_sources_stack_name_environment_id_unique": { + "name": "stack_sources_stack_name_environment_id_unique", + "nullsNotDistinct": false, + "columns": [ + "stack_name", + "environment_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_preferences": { + "name": "user_preferences", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_preferences_user_id_users_id_fk": { + "name": "user_preferences_user_id_users_id_fk", + "tableFrom": "user_preferences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_preferences_environment_id_environments_id_fk": { + "name": "user_preferences_environment_id_environments_id_fk", + "tableFrom": "user_preferences", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_preferences_user_id_environment_id_key_unique": { + "name": "user_preferences_user_id_environment_id_key_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "environment_id", + "key" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_roles": { + "name": "user_roles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_roles_user_id_users_id_fk": { + "name": "user_roles_user_id_users_id_fk", + "tableFrom": "user_roles", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_roles_role_id_roles_id_fk": { + "name": "user_roles_role_id_roles_id_fk", + "tableFrom": "user_roles", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_roles_environment_id_environments_id_fk": { + "name": "user_roles_environment_id_environments_id_fk", + "tableFrom": "user_roles", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_roles_user_id_role_id_environment_id_unique": { + "name": "user_roles_user_id_role_id_environment_id_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "role_id", + "environment_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "avatar": { + "name": "avatar", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "auth_provider": { + "name": "auth_provider", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'local'" + }, + "mfa_enabled": { + "name": "mfa_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "mfa_secret": { + "name": "mfa_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "last_login": { + "name": "last_login", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_username_unique": { + "name": "users_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.vulnerability_scans": { + "name": "vulnerability_scans", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "image_id": { + "name": "image_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "image_name": { + "name": "image_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scanner": { + "name": "scanner", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scanned_at": { + "name": "scanned_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "scan_duration": { + "name": "scan_duration", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "critical_count": { + "name": "critical_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "high_count": { + "name": "high_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "medium_count": { + "name": "medium_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "low_count": { + "name": "low_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "negligible_count": { + "name": "negligible_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "unknown_count": { + "name": "unknown_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "vulnerabilities": { + "name": "vulnerabilities", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "vulnerability_scans_env_image_idx": { + "name": "vulnerability_scans_env_image_idx", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "image_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "vulnerability_scans_environment_id_environments_id_fk": { + "name": "vulnerability_scans_environment_id_environments_id_fk", + "tableFrom": "vulnerability_scans", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle-pg/meta/_journal.json b/drizzle-pg/meta/_journal.json index 33e441a..cc79397 100644 --- a/drizzle-pg/meta/_journal.json +++ b/drizzle-pg/meta/_journal.json @@ -50,6 +50,13 @@ "when": 1777220350655, "tag": "0006_add_git_stack_context_dir", "breakpoints": true + }, + { + "idx": 7, + "version": "7", + "when": 1781158711008, + "tag": "0007_add_synced_files", + "breakpoints": true } ] } \ No newline at end of file diff --git a/drizzle/0007_add_synced_files.sql b/drizzle/0007_add_synced_files.sql new file mode 100644 index 0000000..042b831 --- /dev/null +++ b/drizzle/0007_add_synced_files.sql @@ -0,0 +1 @@ +ALTER TABLE `git_stacks` ADD `synced_files` text; \ No newline at end of file diff --git a/drizzle/meta/0007_snapshot.json b/drizzle/meta/0007_snapshot.json new file mode 100644 index 0000000..6e8cddb --- /dev/null +++ b/drizzle/meta/0007_snapshot.json @@ -0,0 +1,3179 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "58e2bac9-5175-48b0-b757-3932fee17547", + "prevId": "65931916-e53c-4e46-8901-82969a2e6bf0", + "tables": { + "api_tokens": { + "name": "api_tokens", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token_prefix": { + "name": "token_prefix", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_used": { + "name": "last_used", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "api_tokens_token_hash_unique": { + "name": "api_tokens_token_hash_unique", + "columns": [ + "token_hash" + ], + "isUnique": true + }, + "api_tokens_user_id_idx": { + "name": "api_tokens_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "api_tokens_token_prefix_idx": { + "name": "api_tokens_token_prefix_idx", + "columns": [ + "token_prefix" + ], + "isUnique": false + } + }, + "foreignKeys": { + "api_tokens_user_id_users_id_fk": { + "name": "api_tokens_user_id_users_id_fk", + "tableFrom": "api_tokens", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "audit_logs": { + "name": "audit_logs", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "entity_type": { + "name": "entity_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "entity_id": { + "name": "entity_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "entity_name": { + "name": "entity_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "details": { + "name": "details", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "audit_logs_user_id_idx": { + "name": "audit_logs_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "audit_logs_created_at_idx": { + "name": "audit_logs_created_at_idx", + "columns": [ + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": { + "audit_logs_user_id_users_id_fk": { + "name": "audit_logs_user_id_users_id_fk", + "tableFrom": "audit_logs", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "audit_logs_environment_id_environments_id_fk": { + "name": "audit_logs_environment_id_environments_id_fk", + "tableFrom": "audit_logs", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "auth_settings": { + "name": "auth_settings", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "auth_enabled": { + "name": "auth_enabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "default_provider": { + "name": "default_provider", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'local'" + }, + "session_timeout": { + "name": "session_timeout", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 86400 + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "auto_update_settings": { + "name": "auto_update_settings", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "container_name": { + "name": "container_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "schedule_type": { + "name": "schedule_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'daily'" + }, + "cron_expression": { + "name": "cron_expression", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "vulnerability_criteria": { + "name": "vulnerability_criteria", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'never'" + }, + "last_checked": { + "name": "last_checked", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_updated": { + "name": "last_updated", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "auto_update_settings_environment_id_container_name_unique": { + "name": "auto_update_settings_environment_id_container_name_unique", + "columns": [ + "environment_id", + "container_name" + ], + "isUnique": true + } + }, + "foreignKeys": { + "auto_update_settings_environment_id_environments_id_fk": { + "name": "auto_update_settings_environment_id_environments_id_fk", + "tableFrom": "auto_update_settings", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "config_sets": { + "name": "config_sets", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "env_vars": { + "name": "env_vars", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "labels": { + "name": "labels", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ports": { + "name": "ports", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "volumes": { + "name": "volumes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "network_mode": { + "name": "network_mode", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'bridge'" + }, + "restart_policy": { + "name": "restart_policy", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'no'" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "config_sets_name_unique": { + "name": "config_sets_name_unique", + "columns": [ + "name" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "container_events": { + "name": "container_events", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "container_id": { + "name": "container_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "container_name": { + "name": "container_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actor_attributes": { + "name": "actor_attributes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "timestamp": { + "name": "timestamp", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "container_events_env_timestamp_idx": { + "name": "container_events_env_timestamp_idx", + "columns": [ + "environment_id", + "timestamp" + ], + "isUnique": false + } + }, + "foreignKeys": { + "container_events_environment_id_environments_id_fk": { + "name": "container_events_environment_id_environments_id_fk", + "tableFrom": "container_events", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "environment_notifications": { + "name": "environment_notifications", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "notification_id": { + "name": "notification_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": true + }, + "event_types": { + "name": "event_types", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "environment_notifications_environment_id_notification_id_unique": { + "name": "environment_notifications_environment_id_notification_id_unique", + "columns": [ + "environment_id", + "notification_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "environment_notifications_environment_id_environments_id_fk": { + "name": "environment_notifications_environment_id_environments_id_fk", + "tableFrom": "environment_notifications", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "environment_notifications_notification_id_notification_settings_id_fk": { + "name": "environment_notifications_notification_id_notification_settings_id_fk", + "tableFrom": "environment_notifications", + "tableTo": "notification_settings", + "columnsFrom": [ + "notification_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "environments": { + "name": "environments", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 2375 + }, + "protocol": { + "name": "protocol", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'http'" + }, + "tls_ca": { + "name": "tls_ca", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tls_cert": { + "name": "tls_cert", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tls_key": { + "name": "tls_key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tls_skip_verify": { + "name": "tls_skip_verify", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'globe'" + }, + "collect_activity": { + "name": "collect_activity", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": true + }, + "collect_metrics": { + "name": "collect_metrics", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": true + }, + "highlight_changes": { + "name": "highlight_changes", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": true + }, + "labels": { + "name": "labels", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "connection_type": { + "name": "connection_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'socket'" + }, + "socket_path": { + "name": "socket_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'/var/run/docker.sock'" + }, + "hawser_token": { + "name": "hawser_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hawser_last_seen": { + "name": "hawser_last_seen", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hawser_agent_id": { + "name": "hawser_agent_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hawser_agent_name": { + "name": "hawser_agent_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hawser_version": { + "name": "hawser_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hawser_capabilities": { + "name": "hawser_capabilities", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "environments_name_unique": { + "name": "environments_name_unique", + "columns": [ + "name" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "git_credentials": { + "name": "git_credentials", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'none'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ssh_private_key": { + "name": "ssh_private_key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ssh_passphrase": { + "name": "ssh_passphrase", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "git_credentials_name_unique": { + "name": "git_credentials_name_unique", + "columns": [ + "name" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "git_repositories": { + "name": "git_repositories", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'main'" + }, + "credential_id": { + "name": "credential_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "compose_path": { + "name": "compose_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'docker-compose.yml'" + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "auto_update": { + "name": "auto_update", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "auto_update_schedule": { + "name": "auto_update_schedule", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'daily'" + }, + "auto_update_cron": { + "name": "auto_update_cron", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'0 3 * * *'" + }, + "webhook_enabled": { + "name": "webhook_enabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "webhook_secret": { + "name": "webhook_secret", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_sync": { + "name": "last_sync", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_commit": { + "name": "last_commit", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sync_status": { + "name": "sync_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'pending'" + }, + "sync_error": { + "name": "sync_error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "git_repositories_name_unique": { + "name": "git_repositories_name_unique", + "columns": [ + "name" + ], + "isUnique": true + } + }, + "foreignKeys": { + "git_repositories_credential_id_git_credentials_id_fk": { + "name": "git_repositories_credential_id_git_credentials_id_fk", + "tableFrom": "git_repositories", + "tableTo": "git_credentials", + "columnsFrom": [ + "credential_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "git_stacks": { + "name": "git_stacks", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "stack_name": { + "name": "stack_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "repository_id": { + "name": "repository_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "compose_path": { + "name": "compose_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'docker-compose.yml'" + }, + "env_file_path": { + "name": "env_file_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "auto_update": { + "name": "auto_update", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "auto_update_schedule": { + "name": "auto_update_schedule", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'daily'" + }, + "auto_update_cron": { + "name": "auto_update_cron", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'0 3 * * *'" + }, + "webhook_enabled": { + "name": "webhook_enabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "webhook_secret": { + "name": "webhook_secret", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "context_dir": { + "name": "context_dir", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "build_on_deploy": { + "name": "build_on_deploy", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "no_build_cache": { + "name": "no_build_cache", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "repull_images": { + "name": "repull_images", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "force_redeploy": { + "name": "force_redeploy", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "last_sync": { + "name": "last_sync", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_commit": { + "name": "last_commit", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sync_status": { + "name": "sync_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'pending'" + }, + "sync_error": { + "name": "sync_error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "synced_files": { + "name": "synced_files", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "git_stacks_stack_name_environment_id_unique": { + "name": "git_stacks_stack_name_environment_id_unique", + "columns": [ + "stack_name", + "environment_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "git_stacks_environment_id_environments_id_fk": { + "name": "git_stacks_environment_id_environments_id_fk", + "tableFrom": "git_stacks", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "git_stacks_repository_id_git_repositories_id_fk": { + "name": "git_stacks_repository_id_git_repositories_id_fk", + "tableFrom": "git_stacks", + "tableTo": "git_repositories", + "columnsFrom": [ + "repository_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "hawser_tokens": { + "name": "hawser_tokens", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token_prefix": { + "name": "token_prefix", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_active": { + "name": "is_active", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": true + }, + "last_used": { + "name": "last_used", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "hawser_tokens_token_unique": { + "name": "hawser_tokens_token_unique", + "columns": [ + "token" + ], + "isUnique": true + } + }, + "foreignKeys": { + "hawser_tokens_environment_id_environments_id_fk": { + "name": "hawser_tokens_environment_id_environments_id_fk", + "tableFrom": "hawser_tokens", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "host_metrics": { + "name": "host_metrics", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cpu_percent": { + "name": "cpu_percent", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "memory_percent": { + "name": "memory_percent", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "memory_used": { + "name": "memory_used", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "memory_total": { + "name": "memory_total", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "timestamp": { + "name": "timestamp", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "host_metrics_env_timestamp_idx": { + "name": "host_metrics_env_timestamp_idx", + "columns": [ + "environment_id", + "timestamp" + ], + "isUnique": false + } + }, + "foreignKeys": { + "host_metrics_environment_id_environments_id_fk": { + "name": "host_metrics_environment_id_environments_id_fk", + "tableFrom": "host_metrics", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "ldap_config": { + "name": "ldap_config", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "server_url": { + "name": "server_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "bind_dn": { + "name": "bind_dn", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "bind_password": { + "name": "bind_password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "base_dn": { + "name": "base_dn", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_filter": { + "name": "user_filter", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'(uid={{username}})'" + }, + "username_attribute": { + "name": "username_attribute", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'uid'" + }, + "email_attribute": { + "name": "email_attribute", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'mail'" + }, + "display_name_attribute": { + "name": "display_name_attribute", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'cn'" + }, + "group_base_dn": { + "name": "group_base_dn", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "group_filter": { + "name": "group_filter", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "admin_group": { + "name": "admin_group", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role_mappings": { + "name": "role_mappings", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tls_enabled": { + "name": "tls_enabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "tls_ca": { + "name": "tls_ca", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "notification_settings": { + "name": "notification_settings", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": true + }, + "config": { + "name": "config", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_types": { + "name": "event_types", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "oidc_config": { + "name": "oidc_config", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "issuer_url": { + "name": "issuer_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "client_secret": { + "name": "client_secret", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "redirect_uri": { + "name": "redirect_uri", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'openid profile email'" + }, + "username_claim": { + "name": "username_claim", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'preferred_username'" + }, + "email_claim": { + "name": "email_claim", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'email'" + }, + "display_name_claim": { + "name": "display_name_claim", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'name'" + }, + "admin_claim": { + "name": "admin_claim", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "admin_value": { + "name": "admin_value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role_mappings_claim": { + "name": "role_mappings_claim", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'groups'" + }, + "role_mappings": { + "name": "role_mappings", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "pending_container_updates": { + "name": "pending_container_updates", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "container_id": { + "name": "container_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "container_name": { + "name": "container_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "current_image": { + "name": "current_image", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "checked_at": { + "name": "checked_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "pending_container_updates_environment_id_container_id_unique": { + "name": "pending_container_updates_environment_id_container_id_unique", + "columns": [ + "environment_id", + "container_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "pending_container_updates_environment_id_environments_id_fk": { + "name": "pending_container_updates_environment_id_environments_id_fk", + "tableFrom": "pending_container_updates", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "registries": { + "name": "registries", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_default": { + "name": "is_default", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "registries_name_unique": { + "name": "registries_name_unique", + "columns": [ + "name" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "roles": { + "name": "roles", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_system": { + "name": "is_system", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "permissions": { + "name": "permissions", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "environment_ids": { + "name": "environment_ids", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "roles_name_unique": { + "name": "roles_name_unique", + "columns": [ + "name" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "schedule_executions": { + "name": "schedule_executions", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "schedule_type": { + "name": "schedule_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schedule_id": { + "name": "schedule_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "entity_name": { + "name": "entity_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "triggered_by": { + "name": "triggered_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "triggered_at": { + "name": "triggered_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "completed_at": { + "name": "completed_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "duration": { + "name": "duration", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "details": { + "name": "details", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logs": { + "name": "logs", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "schedule_executions_type_id_idx": { + "name": "schedule_executions_type_id_idx", + "columns": [ + "schedule_type", + "schedule_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "schedule_executions_environment_id_environments_id_fk": { + "name": "schedule_executions_environment_id_environments_id_fk", + "tableFrom": "schedule_executions", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "sessions": { + "name": "sessions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "sessions_user_id_idx": { + "name": "sessions_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "sessions_expires_at_idx": { + "name": "sessions_expires_at_idx", + "columns": [ + "expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": { + "sessions_user_id_users_id_fk": { + "name": "sessions_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "settings": { + "name": "settings", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "stack_environment_variables": { + "name": "stack_environment_variables", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "stack_name": { + "name": "stack_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_secret": { + "name": "is_secret", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "stack_environment_variables_stack_name_environment_id_key_unique": { + "name": "stack_environment_variables_stack_name_environment_id_key_unique", + "columns": [ + "stack_name", + "environment_id", + "key" + ], + "isUnique": true + } + }, + "foreignKeys": { + "stack_environment_variables_environment_id_environments_id_fk": { + "name": "stack_environment_variables_environment_id_environments_id_fk", + "tableFrom": "stack_environment_variables", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "stack_events": { + "name": "stack_events", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "stack_name": { + "name": "stack_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "timestamp": { + "name": "timestamp", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "stack_events_environment_id_environments_id_fk": { + "name": "stack_events_environment_id_environments_id_fk", + "tableFrom": "stack_events", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "stack_sources": { + "name": "stack_sources", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "stack_name": { + "name": "stack_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'internal'" + }, + "git_repository_id": { + "name": "git_repository_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "git_stack_id": { + "name": "git_stack_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "compose_path": { + "name": "compose_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "env_path": { + "name": "env_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "stack_sources_stack_name_environment_id_unique": { + "name": "stack_sources_stack_name_environment_id_unique", + "columns": [ + "stack_name", + "environment_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "stack_sources_environment_id_environments_id_fk": { + "name": "stack_sources_environment_id_environments_id_fk", + "tableFrom": "stack_sources", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "stack_sources_git_repository_id_git_repositories_id_fk": { + "name": "stack_sources_git_repository_id_git_repositories_id_fk", + "tableFrom": "stack_sources", + "tableTo": "git_repositories", + "columnsFrom": [ + "git_repository_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "stack_sources_git_stack_id_git_stacks_id_fk": { + "name": "stack_sources_git_stack_id_git_stacks_id_fk", + "tableFrom": "stack_sources", + "tableTo": "git_stacks", + "columnsFrom": [ + "git_stack_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_preferences": { + "name": "user_preferences", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "user_preferences_user_id_environment_id_key_unique": { + "name": "user_preferences_user_id_environment_id_key_unique", + "columns": [ + "user_id", + "environment_id", + "key" + ], + "isUnique": true + } + }, + "foreignKeys": { + "user_preferences_user_id_users_id_fk": { + "name": "user_preferences_user_id_users_id_fk", + "tableFrom": "user_preferences", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_preferences_environment_id_environments_id_fk": { + "name": "user_preferences_environment_id_environments_id_fk", + "tableFrom": "user_preferences", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_roles": { + "name": "user_roles", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role_id": { + "name": "role_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "user_roles_user_id_role_id_environment_id_unique": { + "name": "user_roles_user_id_role_id_environment_id_unique", + "columns": [ + "user_id", + "role_id", + "environment_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "user_roles_user_id_users_id_fk": { + "name": "user_roles_user_id_users_id_fk", + "tableFrom": "user_roles", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_roles_role_id_roles_id_fk": { + "name": "user_roles_role_id_roles_id_fk", + "tableFrom": "user_roles", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_roles_environment_id_environments_id_fk": { + "name": "user_roles_environment_id_environments_id_fk", + "tableFrom": "user_roles", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "avatar": { + "name": "avatar", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "auth_provider": { + "name": "auth_provider", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'local'" + }, + "mfa_enabled": { + "name": "mfa_enabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "mfa_secret": { + "name": "mfa_secret", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_active": { + "name": "is_active", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": true + }, + "last_login": { + "name": "last_login", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "users_username_unique": { + "name": "users_username_unique", + "columns": [ + "username" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "vulnerability_scans": { + "name": "vulnerability_scans", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "environment_id": { + "name": "environment_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image_id": { + "name": "image_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image_name": { + "name": "image_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scanner": { + "name": "scanner", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scanned_at": { + "name": "scanned_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scan_duration": { + "name": "scan_duration", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "critical_count": { + "name": "critical_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "high_count": { + "name": "high_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "medium_count": { + "name": "medium_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "low_count": { + "name": "low_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "negligible_count": { + "name": "negligible_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "unknown_count": { + "name": "unknown_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "vulnerabilities": { + "name": "vulnerabilities", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "vulnerability_scans_env_image_idx": { + "name": "vulnerability_scans_env_image_idx", + "columns": [ + "environment_id", + "image_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "vulnerability_scans_environment_id_environments_id_fk": { + "name": "vulnerability_scans_environment_id_environments_id_fk", + "tableFrom": "vulnerability_scans", + "tableTo": "environments", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index c1a5a0c..9dc7518 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -50,6 +50,13 @@ "when": 1777220350655, "tag": "0006_add_git_stack_context_dir", "breakpoints": true + }, + { + "idx": 7, + "version": "6", + "when": 1781158702731, + "tag": "0007_add_synced_files", + "breakpoints": true } ] } \ No newline at end of file diff --git a/package.json b/package.json index 6b14f4a..9541634 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "dockhand", "private": true, - "version": "1.0.27", + "version": "1.0.33", "type": "module", "scripts": { "dev": "npx vite dev", @@ -63,8 +63,9 @@ "@codemirror/lang-python": "6.2.1", "@codemirror/lang-sql": "6.10.0", "@codemirror/lang-xml": "6.1.0", - "@codemirror/lang-yaml": "6.1.2", + "@codemirror/lang-yaml": "6.1.3", "@codemirror/language": "6.12.1", + "@codemirror/legacy-modes": "6.5.3", "@codemirror/search": "6.6.0", "@codemirror/state": "6.5.4", "@codemirror/theme-one-dark": "6.1.3", diff --git a/server.js b/server.js index 300c6d3..62bdf7a 100644 --- a/server.js +++ b/server.js @@ -8,11 +8,12 @@ * Usage: node ./server.js */ -import { createServer, request as httpRequest } from 'node:http'; -import { request as httpsRequest } from 'node:https'; +import { createServer as createHttpServer, request as httpRequest } from 'node:http'; +import { createServer as createHttpsServer, request as httpsRequest } from 'node:https'; import { createConnection } from 'node:net'; import { connect as tlsConnect, rootCertificates } from 'node:tls'; -import { randomUUID } from 'node:crypto'; +import { randomUUID, X509Certificate } from 'node:crypto'; +import { readFileSync } from 'node:fs'; import { WebSocketServer } from 'ws'; import { handler } from './build/handler.js'; @@ -28,10 +29,82 @@ console.warn = (...args) => _warn(ts(), ...args); const PORT = parseInt(process.env.PORT || '3000', 10); const HOST = process.env.HOST || '0.0.0.0'; -// Create HTTP server with SvelteKit handler -const server = createServer((req, res) => { - handler(req, res); -}); +// Optional native HTTPS listener (#1102). Off by default to keep existing +// deployments unchanged. When HTTPS_MODE=on, HTTPS_CERT_PATH and +// HTTPS_KEY_PATH must both point to readable PEM files. +const HTTPS_MODE = (process.env.HTTPS_MODE || 'off').toLowerCase(); +const useHttps = HTTPS_MODE === 'on'; + +let server; +if (useHttps) { + const certPath = process.env.HTTPS_CERT_PATH; + const keyPath = process.env.HTTPS_KEY_PATH; + const caPath = process.env.HTTPS_CA_PATH; + + console.log('[HTTPS] mode=on'); + console.log(`[HTTPS] cert=${certPath || '(missing)'}`); + console.log(`[HTTPS] key=${keyPath || '(missing)'}`); + console.log(`[HTTPS] ca=${caPath || '(none)'}`); + + if (!certPath || !keyPath) { + console.error('[HTTPS] HTTPS_MODE=on requires HTTPS_CERT_PATH and HTTPS_KEY_PATH'); + process.exit(1); + } + + let certPem, keyPem, caPem; + try { + certPem = readFileSync(certPath); + keyPem = readFileSync(keyPath); + if (caPath) caPem = readFileSync(caPath); + } catch (e) { + console.error(`[HTTPS] Failed to read cert/key file: ${e.message}`); + process.exit(1); + } + + // Parse cert metadata so operators can confirm they mounted the right file. + try { + const x509 = new X509Certificate(certPem); + console.log(`[HTTPS] cert subject: ${x509.subject.replace(/\n/g, ', ')}`); + console.log(`[HTTPS] cert issuer: ${x509.issuer.replace(/\n/g, ', ')}`); + console.log(`[HTTPS] cert SAN: ${x509.subjectAltName || '(none)'}`); + console.log(`[HTTPS] cert valid: ${x509.validFrom} → ${x509.validTo}`); + const expiresAt = new Date(x509.validTo).getTime(); + const daysLeft = Math.floor((expiresAt - Date.now()) / 86400000); + if (daysLeft < 0) { + console.warn(`[HTTPS] WARNING: certificate expired ${-daysLeft} day(s) ago`); + } else if (daysLeft < 30) { + console.warn(`[HTTPS] WARNING: certificate expires in ${daysLeft} day(s)`); + } else { + console.log(`[HTTPS] cert expires in ${daysLeft} day(s)`); + } + } catch (e) { + console.error(`[HTTPS] Failed to parse certificate: ${e.message}`); + process.exit(1); + } + + const tlsOptions = { cert: certPem, key: keyPem }; + if (caPem) tlsOptions.ca = caPem; + + // HSTS — only meaningful over HTTPS, so wired only here. Default 1 year; + // set HSTS_MAX_AGE=0 to disable. + const hstsMaxAge = parseInt(process.env.HSTS_MAX_AGE ?? '31536000', 10); + const hstsHeader = hstsMaxAge > 0 ? `max-age=${hstsMaxAge}` : null; + if (hstsHeader) { + console.log(`[HTTPS] HSTS enabled: ${hstsHeader}`); + } else { + console.log('[HTTPS] HSTS disabled (HSTS_MAX_AGE=0)'); + } + + server = createHttpsServer(tlsOptions, (req, res) => { + if (hstsHeader) res.setHeader('Strict-Transport-Security', hstsHeader); + handler(req, res); + }); +} else { + console.log(`[HTTPS] mode=off (set HTTPS_MODE=on to enable native TLS)`); + server = createHttpServer((req, res) => { + handler(req, res); + }); +} // Create WebSocket server attached to the HTTP server const wss = new WebSocketServer({ noServer: true }); @@ -458,7 +531,8 @@ function handleHawserConnection(ws, connId, remoteIp) { // Start the server server.listen(PORT, HOST, () => { - console.log(`Listening on http://${HOST}:${PORT}/ with WebSocket`); + const scheme = useHttps ? 'https' : 'http'; + console.log(`Listening on ${scheme}://${HOST}:${PORT}/ with WebSocket`); }); diff --git a/src/app.css b/src/app.css index 4650027..7944251 100644 --- a/src/app.css +++ b/src/app.css @@ -1341,6 +1341,16 @@ html { line-height: 14px; } + /* Icon animation toggle (#1169): when html.no-icon-animation is set, the + common Tailwind animation utilities collapse to no-op. This keeps the + layout (spinners still occupy space) but removes the motion. */ + html.no-icon-animation .animate-spin, + html.no-icon-animation .animate-pulse, + html.no-icon-animation .animate-bounce, + html.no-icon-animation .animate-ping { + animation: none !important; + } + /* Icon glow utilities - standard size (4px blur, 0.6 opacity) */ .glow-green { filter: drop-shadow(0 0 4px rgba(34, 197, 94, 0.6)); } .glow-green-sm { filter: drop-shadow(0 0 3px rgba(34, 197, 94, 0.5)); } diff --git a/src/lib/components/AnimateIconsToggle.svelte b/src/lib/components/AnimateIconsToggle.svelte new file mode 100644 index 0000000..4aa6e0e --- /dev/null +++ b/src/lib/components/AnimateIconsToggle.svelte @@ -0,0 +1,37 @@ + + +
Spinners during pulls, scans and updates.
+