doctor

package
v1.0.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 3, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

S77-T08: doctor --deep check for orphaned Hasura remote schemas.

A remote schema is "orphaned" when it is registered in Hasura metadata but the plugin that provides it is no longer installed. This can happen after `nself plugin uninstall <name>` if Hasura metadata was not cleaned up, or after a manual plugin removal. Orphaned remote schemas cause Hasura to emit schema-load errors on startup and break the GraphQL API surface.

Detection strategy:

  1. Read NSELF_HASURA_GRAPHQL_URL (or derive from HASURA_GRAPHQL_URL) to locate the running Hasura instance.
  2. Call the Hasura Metadata API to export remote_schemas (POST /v1/metadata with {"type":"export_metadata","args":{}}). Requires HASURA_GRAPHQL_ADMIN_SECRET.
  3. For each remote schema entry, derive the expected plugin name from the remote schema's URL: internal plugin URLs follow the pattern http://host:PORT where PORT is registered in PLUGIN_<NAME>_INTERNAL_URL.
  4. Cross-reference against loaded plugins: env var NSELF_PLUGINS_LOADED (comma- separated list set by `nself build`) and per-plugin PLUGIN_<NAME>_INTERNAL_URL.
  5. Emit WARN for each orphan found; PASS if none; SKIP if Hasura is unreachable.

The check is read-only — it never modifies Hasura metadata. S77-T08

S69-T05: doctor check for ai+moderation wiring on public-bound deployments.

If the ai plugin is loaded AND the deployment binding is non-loopback AND the moderation plugin is NOT loaded, this emits a WARN. Severity is WARN (not FAIL) because self-hosted single-user setups are legitimate.

Package doctor provides comprehensive health check sections for nself doctor.

Index

Constants

View Source
const (
	// DefaultPostgresMaxConnections is the Postgres default max_connections setting.
	// Operators should raise this in POSTGRES_MAX_CONNECTIONS when running many services.
	DefaultPostgresMaxConnections = 100

	// PoolCapCheckID is the canonical check ID referenced in docs and Alertmanager.
	PoolCapCheckID = "PERF-POOL-01"
)
View Source
const (
	// RLSCheckID is the canonical check ID referenced in docs, wiki, and Alertmanager.
	RLSCheckID = "PERM-RLS-01"
)

Variables

This section is empty.

Functions

func RecommendedPoolSize added in v1.0.11

func RecommendedPoolSize(postgresMaxConnections, numServices int) int

RecommendedPoolSize computes the recommended per-service MaxConns cap.

MaxConns = min(10, floor(postgres_max_connections / num_services))

Edge cases:

  • numServices=0 → returns 10 (no services, no constraint)
  • very large max_connections → capped at 10 (prevents runaway allocations)
  • numServices > max_connections → returns 1 (absolute minimum)

func RecordCITokenRotation added in v1.0.14

func RecordCITokenRotation(projectDir string) error

RecordCITokenRotation writes a new timestamp to the rotation log. Called by `nself doctor --record-ci-token-rotation`. Creates parent dirs as needed.

Types

type CheckResult

type CheckResult struct {
	Section string `json:"section"`
	Name    string `json:"name"`
	Status  string `json:"status"` // pass, warn, fail
	Message string `json:"message"`
	FixCmd  string `json:"fix_cmd,omitempty"` // suggested fix command
}

CheckResult holds the outcome of a single diagnostic check.

func BackupChecks

func BackupChecks(_ context.Context, projectDir string) []CheckResult

BackupChecks verifies backup health.

func CheckAdminBind added in v1.0.11

func CheckAdminBind(ctx context.Context) CheckResult

CheckAdminBind verifies that the nself-admin container is bound to 127.0.0.1 only (not 0.0.0.0 which would expose it to the LAN). This implements S43-T03 — required by the Service Binding Hard Rule.

func CheckCIToken added in v1.0.14

func CheckCIToken(projectDir string) CheckResult

CheckCIToken is the CI-TOKEN-01 deep doctor check.

It verifies:

  1. NSELF_CI_TOKEN is set (in any env cascade file or the environment itself).
  2. A rotation log exists documenting the last time the token was rotated.
  3. Expiry-proximity check (primary): if an "expires <RFC3339>" entry exists in the rotation log, warn at ≤14d remaining and fail at ≤1d remaining.
  4. Rotation-age check (fallback): when no expiry date is present in the log (legacy entries), fall back to the old 90d soft / 120d hard rotation-age logic.

This check is --deep only. It does NOT attempt to call the GitHub API (no network) — it only inspects the local rotation log.

To update the rotation log after a token rotation:

nself doctor --record-ci-token-rotation [--expires <RFC3339>]

(CLI command delegates to internal/doctor.RecordCITokenRotation.)

func CheckCIVaultSync added in v1.0.14

func CheckCIVaultSync(projectDir string) CheckResult

CheckCIVaultSync is the CI-VAULT-SYNC-01 deep doctor check.

It verifies that vault.env or the live environment contains all critical CI PATs (fail on missing) and 180-day infra tokens (warn on missing).

The check does NOT validate token values — only presence. A token could be present but expired; CI-TOKEN-01 handles rotation-age tracking for NSELF_CI_TOKEN specifically. CI-VAULT-SYNC-01 covers the broader vault coverage question.

func CheckEncryptionKeyScope added in v1.0.11

func CheckEncryptionKeyScope(projectDir string, strict bool) []CheckResult

CheckEncryptionKeyScope verifies that AI_ENCRYPTION_KEY (and any other *_ENCRYPTION_KEY env vars) are set and are not reused across environments. Implements S43-UNDEP-01 + S43-AUDIT-01 (SEC-ENC-01 and SEC-ENC-02).

When strict=true, a shared or default key returns Status="fail". When strict=false (default), it returns Status="warn" — allowing the admin to investigate without blocking a deploy.

func CheckHasuraIntrospection added in v1.0.11

func CheckHasuraIntrospection(_ context.Context) CheckResult

CheckHasuraIntrospection implements SEC-HASURA-INTRO-01. It warns if HASURA_GRAPHQL_DISABLE_INTROSPECTION is not set to "true" in a production environment (NSELF_ENV=production or NODE_ENV=production).

The check is:

  • status "skip": environment is dev/staging or NSELF_ENV is unset/empty
  • status "pass": HASURA_GRAPHQL_DISABLE_INTROSPECTION=true in production
  • status "warn": HASURA_GRAPHQL_DISABLE_INTROSPECTION absent or not "true" in production

The check is read-only — it never modifies Hasura configuration. S70-T06

func CheckHasuraMetadataBackup added in v1.0.14

func CheckHasuraMetadataBackup(backupDir string) CheckResult

CheckHasuraMetadataBackup verifies that a hasura-metadata-*.json file exists in backupDir and is less than 36 hours old (implements BACKUP-METADATA-01).

func CheckJWTRotation added in v1.0.14

func CheckJWTRotation(projectDir string) CheckResult

CheckJWTRotation implements the JWT-ROT-01 deep doctor check. It verifies:

  1. HASURA_GRAPHQL_JWT_SECRET is set (delegates to CheckJWTSecretPresent for the precise fail/warn/pass logic on where the key lives).
  2. A rotation log exists at the configured path.
  3. The last recorded rotation is within the configured window (default 90d).

This check is only included in --deep mode.

func CheckJWTSecretPresent added in v1.0.7

func CheckJWTSecretPresent(projectDir string) CheckResult

CheckJWTSecretPresent reports whether HASURA_GRAPHQL_JWT_SECRET is defined in any of the project's env files. Semantics:

  • fail when the key is absent from both .env and .env.secrets and no other env file has it either; this is what the spec calls "Hasura enabled but JWT secret absent from both sources".
  • warn when the key is in .env.secrets but missing from .env. This is the nSelf-preferred arrangement (secrets live in .env.secrets which is gitignored and chmod 0600), so it is informational only.
  • pass when the key is present in .env (with or without .env.secrets).

projectDir is the working directory passed through from `nself doctor`.

func CheckModerationWired added in v1.0.11

func CheckModerationWired(_ context.Context) CheckResult

CheckModerationWired implements S69-T05: warns when the ai plugin is loaded on a public-bound deployment without the moderation plugin also loaded.

Detection logic:

  • ai plugin loaded: NSELF_AI_LOADED=1 OR PLUGIN_AI_INTERNAL_URL non-empty
  • moderation plugin loaded: NSELF_MODERATION_LOADED=1 OR PLUGIN_MODERATION_INTERNAL_URL non-empty
  • public bind: NSELF_BIND_ADDRESS is NOT 127.x / localhost / ::1 / "" (empty = loopback default)

func CheckOrphanRemoteSchemas added in v1.0.11

func CheckOrphanRemoteSchemas(ctx context.Context) CheckResult

CheckOrphanRemoteSchemas implements S77-T08. It queries Hasura metadata and compares registered remote schemas against the currently installed nself plugins. Any remote schema whose providing plugin is absent is flagged as an orphan.

func CheckRLSEnforcement added in v1.0.11

func CheckRLSEnforcement(ctx context.Context, strict bool) []CheckResult

CheckRLSEnforcement implements PERM-RLS-01.

It queries Postgres pg_class for every np_* table and verifies:

(a) RLS is enabled (relrowsecurity = true)
(b) at least one policy exists
(c) PatternTenantScoped tables have FORCE RLS (relforcerowsecurity = true)
(d) tables with tenant_id column have Hasura row filter for that column

Violations are WARN by default. Pass strict=true to escalate to fail.

This check is read-only. It never modifies DB state.

func CheckSDKVersions added in v1.0.14

func CheckSDKVersions(ctx context.Context) []CheckResult

CheckSDKVersions implements the SDK-VERSION-01 deep doctor check. It returns one CheckResult per SDK (4 total), each independently pass / warn / fail so a single drifted SDK does not mask the others.

func CheckSSRF added in v1.0.14

func CheckSSRF(projectDir string) CheckResult

CheckSSRF implements the SSRF-01 deep doctor check. It locates the plugins-pro paid/ directory relative to projectDir and verifies that each plugin service carries effective SSRF guard code (file present + guard symbol present).

projectDir is the nself project working directory (where .env lives). plugins-pro is expected to be a sibling of cli/ inside the nself monorepo.

func DeepChecks

func DeepChecks(ctx context.Context, projectDir string, verbose bool) []CheckResult

DeepChecks runs all 12 subsystem categories for --deep mode.

func DockerDeepChecks

func DockerDeepChecks(ctx context.Context, verbose bool) []CheckResult

DockerDeepChecks verifies daemon, storage driver, dangling images, container health.

func DogfoodChecks added in v1.0.13

func DogfoodChecks(ctx context.Context, projectDir string, verbose bool) []CheckResult

DogfoodChecks runs the full dogfood-only check set. It is invoked from DeepChecks when NSELF_DOGFOOD=1 is set, AND can be invoked directly from CI to gate nself.org's own deploys.

Check IDs (cross-referenced in operations/dogfood-checks.md):

SEC-CSP-01    — CSP headers present on all subapps
SEC-HSTS-01   — HSTS preload value
SEC-AUTH-01   — HttpOnly cookie convention enforced
VENDOR-DEP-01 — no AGPL/SSPL deps in production source
DOGFOOD-SUBAPPS-01 — every shipped subapp has synced sport.json
DOGFOOD-HEX-01     — no hex colors in subapp src/ trees
DOGFOOD-LICENSE-01 — owner license vault path readable

PERM-RLS-01 is intentionally NOT duplicated here; rls_check.go owns it.

func FilterBySection

func FilterBySection(results []CheckResult, section string) []CheckResult

FilterBySection returns only checks matching the given section name.

func FixItEngine

func FixItEngine(ctx context.Context, results []CheckResult) []CheckResult

FixItEngine runs safe auto-fixes for check results that have FixCmd set.

func HasuraChecks

func HasuraChecks(ctx context.Context, verbose bool) []CheckResult

HasuraChecks verifies /healthz 200 and metadata consistency.

func HostChecks

func HostChecks(ctx context.Context, verbose bool) []CheckResult

HostChecks verifies disk, memory, CPU, time sync, kernel.

func LicenseChecks

func LicenseChecks(ctx context.Context, projectDir string, verbose bool) []CheckResult

LicenseChecks verifies license is current and tier matches expected.

func MonitoringChecks

func MonitoringChecks(ctx context.Context) []CheckResult

MonitoringChecks verifies monitoring stack health.

func NginxChecks

func NginxChecks(ctx context.Context, verbose bool) []CheckResult

NginxChecks verifies config test and SSL cert expiry.

func PingChecks

func PingChecks(ctx context.Context, verbose bool) []CheckResult

PingChecks verifies ping.nself.org reachable and license cache fresh.

func PluginHealthChecks

func PluginHealthChecks(ctx context.Context, projectDir string, verbose bool) []CheckResult

PluginHealthChecks verifies every installed plugin's health endpoint.

func PoolCapacityCheck added in v1.0.11

func PoolCapacityCheck(_ context.Context, pools []PoolConfig, postgresMaxConnections int) CheckResult

PoolCapacityCheck verifies that the total configured pgxpool connections across all active services do not exceed postgres_max_connections.

Returns a CheckResult with:

  • Status "pass" when total_conns ≤ postgres_max_connections
  • Status "warn" when total_conns > postgres_max_connections (not a hard block)
  • Status "fail" when inputs are invalid (zero services, negative max)

This check fires in nself doctor --deep as PERF-POOL-01.

func PostgresChecks

func PostgresChecks(ctx context.Context, verbose bool) []CheckResult

PostgresChecks verifies pg_isready, replication lag, longest query, dead tuples, vacuum.

func SSLChecks

func SSLChecks(ctx context.Context, verbose bool) []CheckResult

SSLChecks verifies LE renewal cron, last renewal, OCSP stapling.

func SecurityChecks

func SecurityChecks(ctx context.Context, projectDir string) []CheckResult

SecurityChecks runs security diagnostics.

func SystemChecks

func SystemChecks(ctx context.Context, verbose bool) []CheckResult

SystemChecks runs system-level diagnostics: disk, memory, swap, load, clock sync, Docker, kernel.

type PoolConfig added in v1.0.11

type PoolConfig struct {
	ServiceName string
	MaxConns    int // per-service pgxpool MaxConns (0 = use pgxpoolDefaultMaxConns)
}

PoolConfig describes the pool sizing input for a single service. Each plugin or required service exposes one pool config.

func DefaultPoolConfigs added in v1.0.11

func DefaultPoolConfigs(services []string) []PoolConfig

DefaultPoolConfigs returns a pool config slice for the standard nSelf service set (4 required + up to 7 optional). Pass only the enabled services. Used by nself doctor --deep to compute the PERF-POOL-01 check.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL