From 3e6c80f497c0a78511b68b830ad097c0f3b67e81 Mon Sep 17 00:00:00 2001 From: adhinaik13 <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 19:36:19 +0530 Subject: [PATCH 01/43] fix: complete Doppler Compose integration --- .github/workflows/ci.yml | 2 + README.md | 11 ++++ compose.yaml | 21 +++---- docs/integrations.md | 25 ++++++--- scripts/validate_doppler_config.py | 88 ++++++++++++++++++++++++++++++ src/fluxqueue/config.py | 30 +++++++++- tests/test_config.py | 20 +++++++ 7 files changed, 178 insertions(+), 19 deletions(-) create mode 100644 scripts/validate_doppler_config.py create mode 100644 tests/test_config.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ac5d075..247b6a7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,6 +54,8 @@ jobs: retention-days: 14 - name: Validate Docker Compose configuration run: docker compose config --quiet + - name: Validate Doppler-to-service environment wiring + run: python scripts/validate_doppler_config.py - name: Build container image run: docker build --tag fluxqueue-ci . - name: Verify container runs as non-root diff --git a/README.md b/README.md index 64ca67a..3aa4fce 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,17 @@ The worker polls the same PostgreSQL database and executes registered task types The Compose database password is a local-development default. Set `POSTGRES_PASSWORD` before shared use. For local development, `API_KEY` is optional. For production, set `APP_ENV=production` and configure `API_KEYS` as a JSON object mapping each high-entropy bearer key to a tenant identifier, for example `{"replace-with-a-long-random-secret":"tenant-a"}`. Send the key as `Authorization: Bearer `. The legacy `API_KEY` setting is retained for single-tenant deployments and maps to the `default` tenant; it does not provide tenant isolation by itself. When `API_KEYS` is non-empty, it takes precedence and the legacy key is not accepted. Store keys in Doppler or another secret manager, never in committed files. +For Doppler-backed Compose startup, configure project `fluxqueue`, config `dev`, and at least `POSTGRES_PASSWORD`, `APP_ENV`, `API_KEYS`, and optionally `MAX_ACTIVE_JOBS_PER_TENANT` in that config. From the repository root, authenticate with `doppler login`, then run `doppler setup --no-interactive` and verify without printing secret values: + +```bash +doppler run -- python scripts/validate_doppler_config.py --require-doppler-env +doppler run -- docker compose up --build -d +curl --fail http://127.0.0.1:8000/health/ready +docker compose ps +``` + +The API and worker receive the same resolved database/application environment, while PostgreSQL receives `POSTGRES_PASSWORD`. The validator checks this wiring and emits only variable names and safe diagnostics. + ## API - `POST /api/v1/jobs` diff --git a/compose.yaml b/compose.yaml index 4b20814..ae823df 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,3 +1,11 @@ +x-fluxqueue-environment: &fluxqueue-environment + DATABASE_URL: ${DATABASE_URL:-} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-fluxqueue-local-only} + APP_ENV: ${APP_ENV:-development} + API_KEY: ${API_KEY:-} + API_KEYS: ${API_KEYS:-{}} + MAX_ACTIVE_JOBS_PER_TENANT: ${MAX_ACTIVE_JOBS_PER_TENANT:-1000} + services: db: image: postgres:16-alpine @@ -19,14 +27,9 @@ services: api: build: . restart: unless-stopped - environment: - DATABASE_URL: postgresql+psycopg://fluxqueue:${POSTGRES_PASSWORD:-fluxqueue-local-only}@db:5432/fluxqueue - APP_ENV: ${APP_ENV:-development} - API_KEY: ${API_KEY:-} - API_KEYS: ${API_KEYS:-{}} - MAX_ACTIVE_JOBS_PER_TENANT: ${MAX_ACTIVE_JOBS_PER_TENANT:-1000} + environment: *fluxqueue-environment ports: - - "127.0.0.1:8000:8000" + - "127.0.0.1:${FLUXQUEUE_API_PORT:-8000}:8000" depends_on: db: condition: service_healthy @@ -40,9 +43,7 @@ services: worker: build: . command: ["python", "-m", "fluxqueue.worker"] - environment: - DATABASE_URL: postgresql+psycopg://fluxqueue:${POSTGRES_PASSWORD:-fluxqueue-local-only}@db:5432/fluxqueue - APP_ENV: development + environment: *fluxqueue-environment depends_on: api: condition: service_healthy diff --git a/docs/integrations.md b/docs/integrations.md index 971d4e4..f896dbf 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -18,17 +18,18 @@ Keep the token only in GitHub Actions secrets; never commit it or paste it into ## Doppler -The root `doppler.yaml` maps this repository to the Doppler project `fluxqueue`, config `dev`. This file is only a local CLI mapping; it does not create the project/config or prove the workspace is connected. +The root `doppler.yaml` maps this repository to the Doppler project `fluxqueue`, config `dev`. The mapping is intentionally the same in every setup instruction. It is only a local CLI mapping; it does not create the project/config or prove the workspace is connected. ### One-time workspace setup 1. In the Doppler dashboard, create a project named `fluxqueue` and a config named `dev` (or adjust `doppler.yaml` to match your actual names). 2. Add these values to the `dev` config: - - `POSTGRES_PASSWORD`: a unique local-development password, not the Compose fallback. - - `APP_ENV`: `development`. + - `POSTGRES_PASSWORD`: a non-empty local-development password, not the Compose fallback. Compose passes it separately and FluxQueue safely URL-encodes it when building the local database URL. + - `APP_ENV`: `development` for this local stack. - `API_KEYS`: `{}` for local unauthenticated development, or a JSON object mapping high-entropy bearer keys to tenant IDs for authenticated testing. - `MAX_ACTIVE_JOBS_PER_TENANT`: `1000` (optional; this is the application default). -3. Do not paste Doppler service tokens into GitHub source files, issues, logs, or chat. Use the Doppler CLI login flow for a developer machine; use a narrowly scoped service token only in a secret store for automation/deployments. + - `DATABASE_URL`: optional. If omitted, FluxQueue builds the PostgreSQL URL from `POSTGRES_PASSWORD`; supplying it is useful when the database is not the Compose `db` service. +3. Do not paste Doppler service tokens into GitHub source files, issues, logs, or chat. Use the Doppler CLI login flow for a developer machine; use a narrowly scoped service token only in a secret store for automation/deployments. No Doppler token is required by this repository's CI workflow. ### Verify locally @@ -36,12 +37,22 @@ Install the Doppler CLI and authenticate with `doppler login`. From the reposito ```bash doppler setup --no-interactive -doppler secrets +doppler run -- python scripts/validate_doppler_config.py --require-doppler-env doppler run -- docker compose config --quiet -doppler run -- docker compose up --build +doppler run -- docker compose up --build -d +docker compose ps +curl --fail http://127.0.0.1:8000/health/ready ``` -Confirm the services become healthy, then check `http://127.0.0.1:8000/health/ready`. Stop the stack with `docker compose down` when finished. Never run `docker compose down -v` against a database whose data must be retained. +The validator checks the `fluxqueue`/`dev` mapping and confirms the required environment names are wired to API, worker, and PostgreSQL. With `--require-doppler-env`, it also requires a non-empty injected `POSTGRES_PASSWORD`. It never prints resolved environment values. Confirm the API readiness response and `docker compose ps` show healthy services. Stop the stack with `docker compose down` when finished. Never run `docker compose down -v` against a database whose data must be retained. + +### Troubleshooting Doppler/Compose + +- `POSTGRES_PASSWORD was not injected`: run `doppler login`, repeat `doppler setup --no-interactive`, and verify the selected project is `fluxqueue` and config is `dev`. Do not work around this by committing a token or password. +- `docker compose config failed`: run `docker compose config --quiet` without Doppler to isolate Compose syntax, then rerun through `doppler run`. Check that `API_KEYS` is valid JSON. If supplying `DATABASE_URL` directly, URL-encode its password component. +- API readiness fails while PostgreSQL is healthy: inspect `docker compose logs --no-log-prefix api` for non-secret error text and verify `DATABASE_URL` points at `db` when using the included PostgreSQL service. Never use `docker compose config` output as a log artifact because it contains resolved secrets. +- Worker is unhealthy or idle: check `docker compose logs --no-log-prefix worker`; the worker shares the API's resolved database/application environment and does not need a separate token. +- A changed Doppler value is not active: restart or recreate the services; settings are read at process startup. ### Production boundary diff --git a/scripts/validate_doppler_config.py b/scripts/validate_doppler_config.py new file mode 100644 index 0000000..e63b2a8 --- /dev/null +++ b/scripts/validate_doppler_config.py @@ -0,0 +1,88 @@ +"""Validate secret-manager-to-Compose wiring without printing secret values.""" + +from __future__ import annotations + +import argparse +import json +import os +import subprocess +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +REQUIRED_DOPPLER_MAPPING = ("project: fluxqueue", "config: dev") +SERVICE_ENVIRONMENT = { + "api": { + "DATABASE_URL", + "POSTGRES_PASSWORD", + "APP_ENV", + "API_KEY", + "API_KEYS", + "MAX_ACTIVE_JOBS_PER_TENANT", + }, + "worker": { + "DATABASE_URL", + "POSTGRES_PASSWORD", + "APP_ENV", + "API_KEY", + "API_KEYS", + "MAX_ACTIVE_JOBS_PER_TENANT", + }, + "db": {"POSTGRES_DB", "POSTGRES_USER", "POSTGRES_PASSWORD"}, +} + + +def fail(message: str) -> int: + print(f"Doppler/Compose configuration error: {message}", file=sys.stderr) + return 1 + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--require-doppler-env", + action="store_true", + help="require the non-empty POSTGRES_PASSWORD environment variable", + ) + args = parser.parse_args() + + if args.require_doppler_env and not os.environ.get("POSTGRES_PASSWORD"): + return fail("POSTGRES_PASSWORD was not injected; authenticate Doppler and check config dev") + + doppler_config = (ROOT / "doppler.yaml").read_text(encoding="utf-8") + missing_mapping = [entry for entry in REQUIRED_DOPPLER_MAPPING if entry not in doppler_config] + if missing_mapping: + return fail("doppler.yaml must reference project fluxqueue and config dev") + + result = subprocess.run( + ["docker", "compose", "config", "--format", "json"], + cwd=ROOT, + capture_output=True, + text=True, + check=False, + ) + if result.returncode: + return fail("docker compose config failed; check Compose syntax and variable names") + + try: + document = json.loads(result.stdout) + except json.JSONDecodeError: + return fail("docker compose returned invalid configuration data") + + services = document.get("services", {}) + for service, required in SERVICE_ENVIRONMENT.items(): + environment = services.get(service, {}).get("environment", {}) + present = set(environment) if isinstance(environment, dict) else set() + missing = sorted(required - present) + if missing: + return fail(f"service {service} is missing environment mappings: {', '.join(missing)}") + + print( + "Doppler/Compose configuration is valid; required mappings are present for " + "api, worker, and db." + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/fluxqueue/config.py b/src/fluxqueue/config.py index b72a707..8ab6304 100644 --- a/src/fluxqueue/config.py +++ b/src/fluxqueue/config.py @@ -1,19 +1,45 @@ """Runtime settings with production fail-closed checks.""" +from urllib.parse import quote + from pydantic import Field, model_validator from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): - model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore") + model_config = SettingsConfigDict( + env_file=".env", + env_file_encoding="utf-8", + extra="ignore", + hide_input_in_errors=True, + ) app_env: str = "development" - database_url: str = "sqlite:///./fluxqueue.db" + database_url: str | None = None + postgres_password: str | None = None + database_host: str = "db" + database_port: int = 5432 + database_name: str = "fluxqueue" + database_user: str = "fluxqueue" log_level: str = "INFO" api_key: str | None = None api_keys: dict[str, str] = Field(default_factory=dict) max_active_jobs_per_tenant: int = Field(default=1000, ge=1) + @model_validator(mode="after") + def derive_database_url(self): + if not self.database_url: + if self.postgres_password: + password = quote(self.postgres_password, safe="") + self.database_url = ( + f"postgresql+psycopg://{quote(self.database_user, safe='')}:{password}" + f"@{self.database_host}:{self.database_port}/" + f"{quote(self.database_name, safe='')}" + ) + else: + self.database_url = "sqlite:///./fluxqueue.db" + return self + @model_validator(mode="after") def validate_authentication_settings(self): is_production = self.app_env.lower() in {"production", "prod"} diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 0000000..e6a5199 --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,20 @@ +"""Runtime configuration safety checks.""" + +from fluxqueue.config import Settings + + +def test_database_password_is_url_encoded_when_compose_builds_url(): + configured = Settings(postgres_password="p@ss:word/with?chars#") + + assert configured.database_url == ( + "postgresql+psycopg://fluxqueue:p%40ss%3Aword%2Fwith%3Fchars%23@db:5432/fluxqueue" + ) + + +def test_explicit_database_url_takes_precedence_over_compose_components(): + configured = Settings( + database_url="postgresql+psycopg://external.example/fluxqueue", + postgres_password="unused", + ) + + assert configured.database_url == "postgresql+psycopg://external.example/fluxqueue" From 52dc8b3a48e9b1a5db4360111bf666acce6f5244 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 19:39:24 +0530 Subject: [PATCH 02/43] test: isolate derived database URL check from CI environment --- tests/test_config.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_config.py b/tests/test_config.py index e6a5199..597045c 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -3,7 +3,10 @@ from fluxqueue.config import Settings -def test_database_password_is_url_encoded_when_compose_builds_url(): +def test_database_password_is_url_encoded_when_compose_builds_url(monkeypatch): + # CI sets DATABASE_URL globally for the SQLite test suite; clear it so this + # focused test exercises the PostgreSQL URL derived from the supplied secret. + monkeypatch.delenv("DATABASE_URL", raising=False) configured = Settings(postgres_password="p@ss:word/with?chars#") assert configured.database_url == ( From cfb7b56ba6f9623fcdb51f680f1aed8017b0cb0d Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 19:41:41 +0530 Subject: [PATCH 03/43] docs: add actionable CodeScene integration verification --- docs/integrations.md | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/docs/integrations.md b/docs/integrations.md index f896dbf..ca09635 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -12,7 +12,7 @@ JUnit test results and coverage XML are uploaded as workflow artifacts when avai The repository includes `.codecov.yml` and generates `coverage.xml` in GitHub Actions. The workflow uses the official Codecov Action and authenticates with the repository Actions secret `CODECOV_TOKEN`. -The upload was verified in GitHub Actions run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655): Codecov found `coverage.xml`, accepted the 3.6 KB upload, and reported **“Upload queued for processing complete.”** The report is queued for processing and can be viewed at the [Codecov commit report](https://app.codecov.io/github/vankudothuadhinaik/fluxqueue/commit/f5f6d93ee5212900ead0cfd9a79aa100d2ac91c5). +The upload was verified in GitHub Actions run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655): Codecov found `coverage.xml`, accepted the 3.6 KB upload, and reported **“Upload queued for processing complete.”** The report was queued for processing and can be viewed at the [Codecov commit report](https://app.codecov.io/github/vankudothuadhinaik/fluxqueue/commit/f5f6d93ee5212900ead0cfd9a79aa100d2ac91c5). Keep the token only in GitHub Actions secrets; never commit it or paste it into source files, issues, or chat. Because the token appeared in a screenshot shared during setup, rotate/regenerate it in Codecov and replace the `CODECOV_TOKEN` repository secret with the new value. Then rerun CI to verify the rotated token works. Official guidance: https://github.com/codecov/codecov-action @@ -60,7 +60,24 @@ Create a separate production config; do not reuse `dev`. Set `APP_ENV=production ## CodeScene -CodeScene analysis is managed by the CodeScene GitHub integration and workspace settings, not by a repository token committed to source control. Once the private repository is connected in CodeScene, use its pull-request/code-health findings alongside CI and CodeQL. This repository does not claim CodeScene analysis is active until the service reports a successful analysis. +CodeScene must be connected through its workspace and GitHub integration; do not add a CodeScene token or private key to this repository. For GitHub.com, use the official [CodeScene Access GitHub App](https://github.com/apps/codescene-access/installations/new) where possible. It is the current recommended app for repository access and pull-request checks. + +### Connect and verify + +1. Sign in to [CodeScene](https://codescene.io/) using the GitHub account that owns or can access `vankudothuadhinaik/FluxQueue`. +2. Install/authorize **CodeScene Access** for the FluxQueue repository. Grant access only to the repositories you intend CodeScene to analyze. +3. In CodeScene, create a project and select `vankudothuadhinaik/FluxQueue`; launch the initial analysis and wait for a successful result. +4. If pull-request checks are desired, open the project's **Pull Request Integration** settings and enable GitHub PR integration using CodeScene's supported GitHub App flow. Confirm the app has access to this repository. +5. Verify an analysis result in CodeScene and, for PR integration, verify CodeScene posts a check/review on a newly opened or updated PR. The GitHub Actions jobs in this repository do not substitute for a CodeScene analysis. + +If FluxQueue is not listed, check which GitHub account is connected to CodeScene and whether the CodeScene Access app installation includes this repository. Private repository analysis may depend on the CodeScene plan. Do not create a custom GitHub App or store a private key unless the CodeScene setup flow specifically requires it. + +**Verification status:** CodeScene is not yet confirmed active. The repository has no verified CodeScene analysis or PR check in the CI evidence available to this project. Mark this integration complete only after the workspace shows a successful FluxQueue analysis (and a PR check, if enabled). + +Official references: +- [CodeScene getting started](https://codescene.io/docs/getting-started/index.html) +- [CodeScene GitHub hosting integration](https://www.codescene.io/docs/providers/index.html) +- [CodeScene Access vs. Delta Analysis](https://helpcenter.codescene.com/articles/9262058-codescene-access-vs-codescene-delta-analysis-which-github-app-do) ## Copilot and Codex @@ -68,10 +85,9 @@ Copilot and Codex are development assistants, not runtime dependencies. Keep the ## Current integration status -- GitHub Actions workflows and report artifacts: configured in source. -- CodeQL: configured in the CI workflow; result must be checked on the actual run. -- Python dependency audit: configured in the CI workflow; result must be checked on the actual run. -- Codecov: coverage upload accepted and queued for processing in run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655); rotate the token exposed in the setup screenshot, update `CODECOV_TOKEN`, and rerun CI. -- Doppler: repository mapping ready; requires a matching Doppler project/config and authenticated CLI or deployment service token. -- CodeScene: requires the repository to be connected and analyzed in the CodeScene workspace. +- GitHub Actions: configured; latest PR CI run [40888695203](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40888695203) passed all four jobs. +- CodeQL and Python dependency audit: passed in the latest PR CI run above. +- Codecov: coverage upload was accepted and queued for processing in run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655). The token exposed in the setup screenshot should be rotated and `CODECOV_TOKEN` updated; do not claim rotation is verified until a run succeeds with the replacement token. +- Doppler: project/config injection was reported verified in the PR's local smoke test; CI validates service wiring without requiring a Doppler token. +- CodeScene: setup instructions are documented, but the account-side repository connection and successful analysis remain unverified. - Render/other deployment: no production service is created by these files. Deploying a public service requires a deliberate environment, database, and cost decision. From ec9f5519917302ef0a7d1cb9f99bea9a51e333ad Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 20:01:10 +0530 Subject: [PATCH 04/43] docs: record CodeScene analysis and latest CI status --- docs/integrations.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/integrations.md b/docs/integrations.md index ca09635..110b5b7 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -72,7 +72,7 @@ CodeScene must be connected through its workspace and GitHub integration; do not If FluxQueue is not listed, check which GitHub account is connected to CodeScene and whether the CodeScene Access app installation includes this repository. Private repository analysis may depend on the CodeScene plan. Do not create a custom GitHub App or store a private key unless the CodeScene setup flow specifically requires it. -**Verification status:** CodeScene is not yet confirmed active. The repository has no verified CodeScene analysis or PR check in the CI evidence available to this project. Mark this integration complete only after the workspace shows a successful FluxQueue analysis (and a PR check, if enabled). +**Verification status (2026-10-29):** The FluxQueue project dashboard shows a successful analysis dated October 29, 2026, with average code health 9.4 and hotspot code health 9.6. The dashboard still offers “Set up PR integration,” and GitHub's latest PR check-run list does not contain a CodeScene check. Treat analysis as verified, but PR checks as pending until a CodeScene check/review appears on a pull request. Official references: - [CodeScene getting started](https://codescene.io/docs/getting-started/index.html) @@ -85,9 +85,9 @@ Copilot and Codex are development assistants, not runtime dependencies. Keep the ## Current integration status -- GitHub Actions: configured; latest PR CI run [40888695203](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40888695203) passed all four jobs. +- GitHub Actions: configured; latest PR CI run [40889069383](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40889069383) passed all four jobs on commit `cfb7b56`. - CodeQL and Python dependency audit: passed in the latest PR CI run above. - Codecov: coverage upload was accepted and queued for processing in run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655). The token exposed in the setup screenshot should be rotated and `CODECOV_TOKEN` updated; do not claim rotation is verified until a run succeeds with the replacement token. - Doppler: project/config injection was reported verified in the PR's local smoke test; CI validates service wiring without requiring a Doppler token. -- CodeScene: setup instructions are documented, but the account-side repository connection and successful analysis remain unverified. +- CodeScene: initial FluxQueue analysis is confirmed in the workspace dashboard; GitHub pull-request checks remain unverified/pending. - Render/other deployment: no production service is created by these files. Deploying a public service requires a deliberate environment, database, and cost decision. From 8c9f5c4beb5f61ca5c3c10da11c170772b252307 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 20:03:32 +0530 Subject: [PATCH 05/43] refactor: simplify Doppler validator for CodeScene quality gate --- scripts/validate_doppler_config.py | 65 ++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/scripts/validate_doppler_config.py b/scripts/validate_doppler_config.py index e63b2a8..cf0e106 100644 --- a/scripts/validate_doppler_config.py +++ b/scripts/validate_doppler_config.py @@ -8,6 +8,7 @@ import subprocess import sys from pathlib import Path +from typing import Any ROOT = Path(__file__).resolve().parents[1] REQUIRED_DOPPLER_MAPPING = ("project: fluxqueue", "config: dev") @@ -33,27 +34,42 @@ def fail(message: str) -> int: + """Emit a safe diagnostic and return a failing exit code.""" print(f"Doppler/Compose configuration error: {message}", file=sys.stderr) return 1 -def main() -> int: +def parse_args() -> argparse.Namespace: + """Parse the supported validation options.""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( "--require-doppler-env", action="store_true", help="require the non-empty POSTGRES_PASSWORD environment variable", ) - args = parser.parse_args() + return parser.parse_args() + + +def validate_doppler_environment(required: bool) -> int: + """Check required secret injection without revealing the secret.""" + if required and not os.environ.get("POSTGRES_PASSWORD"): + return fail( + "POSTGRES_PASSWORD was not injected; authenticate Doppler and check config dev" + ) + return 0 - if args.require_doppler_env and not os.environ.get("POSTGRES_PASSWORD"): - return fail("POSTGRES_PASSWORD was not injected; authenticate Doppler and check config dev") - doppler_config = (ROOT / "doppler.yaml").read_text(encoding="utf-8") - missing_mapping = [entry for entry in REQUIRED_DOPPLER_MAPPING if entry not in doppler_config] - if missing_mapping: +def validate_project_mapping() -> int: + """Ensure the repository mapping points at the expected Doppler config.""" + config_path = ROOT / "doppler.yaml" + config = config_path.read_text(encoding="utf-8") + if any(entry not in config for entry in REQUIRED_DOPPLER_MAPPING): return fail("doppler.yaml must reference project fluxqueue and config dev") + return 0 + +def load_compose_configuration() -> dict[str, Any] | None: + """Resolve Compose configuration while keeping its potentially secret output private.""" result = subprocess.run( ["docker", "compose", "config", "--format", "json"], cwd=ROOT, @@ -62,21 +78,46 @@ def main() -> int: check=False, ) if result.returncode: - return fail("docker compose config failed; check Compose syntax and variable names") - + fail("docker compose config failed; check Compose syntax and variable names") + return None try: document = json.loads(result.stdout) except json.JSONDecodeError: - return fail("docker compose returned invalid configuration data") + fail("docker compose returned invalid configuration data") + return None + if not isinstance(document, dict): + fail("docker compose returned an unexpected configuration shape") + return None + return document + +def validate_service_environment(document: dict[str, Any]) -> int: + """Check that API, worker, and database services declare required variables.""" services = document.get("services", {}) for service, required in SERVICE_ENVIRONMENT.items(): - environment = services.get(service, {}).get("environment", {}) + definition = services.get(service, {}) + environment = definition.get("environment", {}) if isinstance(definition, dict) else {} present = set(environment) if isinstance(environment, dict) else set() missing = sorted(required - present) if missing: - return fail(f"service {service} is missing environment mappings: {', '.join(missing)}") + return fail( + f"service {service} is missing environment mappings: {', '.join(missing)}" + ) + return 0 + +def main() -> int: + """Run the independent validation stages.""" + args = parse_args() + if validate_doppler_environment(args.require_doppler_env): + return 1 + if validate_project_mapping(): + return 1 + document = load_compose_configuration() + if document is None: + return 1 + if validate_service_environment(document): + return 1 print( "Doppler/Compose configuration is valid; required mappings are present for " "api, worker, and db." From e07cb29f8d8d3c2fa17ed063ae2054c3e744e64a Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 20:08:49 +0530 Subject: [PATCH 06/43] style: format Doppler validator for CI --- scripts/validate_doppler_config.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scripts/validate_doppler_config.py b/scripts/validate_doppler_config.py index cf0e106..3c235f1 100644 --- a/scripts/validate_doppler_config.py +++ b/scripts/validate_doppler_config.py @@ -53,9 +53,7 @@ def parse_args() -> argparse.Namespace: def validate_doppler_environment(required: bool) -> int: """Check required secret injection without revealing the secret.""" if required and not os.environ.get("POSTGRES_PASSWORD"): - return fail( - "POSTGRES_PASSWORD was not injected; authenticate Doppler and check config dev" - ) + return fail("POSTGRES_PASSWORD was not injected; authenticate Doppler and check config dev") return 0 @@ -100,9 +98,7 @@ def validate_service_environment(document: dict[str, Any]) -> int: present = set(environment) if isinstance(environment, dict) else set() missing = sorted(required - present) if missing: - return fail( - f"service {service} is missing environment mappings: {', '.join(missing)}" - ) + return fail(f"service {service} is missing environment mappings: {', '.join(missing)}") return 0 From 81b567b413a744044528af75d19d6772d19194aa Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 20:15:51 +0530 Subject: [PATCH 07/43] docs: record verified CodeScene PR integration and CI status --- docs/integrations.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/integrations.md b/docs/integrations.md index 110b5b7..2b40a09 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -72,7 +72,7 @@ CodeScene must be connected through its workspace and GitHub integration; do not If FluxQueue is not listed, check which GitHub account is connected to CodeScene and whether the CodeScene Access app installation includes this repository. Private repository analysis may depend on the CodeScene plan. Do not create a custom GitHub App or store a private key unless the CodeScene setup flow specifically requires it. -**Verification status (2026-10-29):** The FluxQueue project dashboard shows a successful analysis dated October 29, 2026, with average code health 9.4 and hotspot code health 9.6. The dashboard still offers “Set up PR integration,” and GitHub's latest PR check-run list does not contain a CodeScene check. Treat analysis as verified, but PR checks as pending until a CodeScene check/review appears on a pull request. +**Verification status (2026-10-29):** The FluxQueue project dashboard shows a successful analysis dated October 29, 2026, with average code health 9.4 and hotspot code health 9.6. The GitHub PR check is now verified: CodeScene posted `CodeScene Code Health Review (main)` on PR #17 and the latest review passed all three quality gates after the Doppler validator was refactored. See [latest CodeScene result](https://codescene.io/projects/87037/delta/results/8191366). Official references: - [CodeScene getting started](https://codescene.io/docs/getting-started/index.html) @@ -85,9 +85,9 @@ Copilot and Codex are development assistants, not runtime dependencies. Keep the ## Current integration status -- GitHub Actions: configured; latest PR CI run [40889069383](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40889069383) passed all four jobs on commit `cfb7b56`. +- GitHub Actions: configured; latest PR CI run [40893582266](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40893582266) passed all four jobs on commit `e07cb29`. - CodeQL and Python dependency audit: passed in the latest PR CI run above. - Codecov: coverage upload was accepted and queued for processing in run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655). The token exposed in the setup screenshot should be rotated and `CODECOV_TOKEN` updated; do not claim rotation is verified until a run succeeds with the replacement token. - Doppler: project/config injection was reported verified in the PR's local smoke test; CI validates service wiring without requiring a Doppler token. -- CodeScene: initial FluxQueue analysis is confirmed in the workspace dashboard; GitHub pull-request checks remain unverified/pending. +- CodeScene: PR integration is active; the latest review on PR #17 passed all three quality gates ([result](https://codescene.io/projects/87037/delta/results/8191366)). - Render/other deployment: no production service is created by these files. Deploying a public service requires a deliberate environment, database, and cost decision. From 7d49409b4273bc56afc1af00435d23d280ece5d7 Mon Sep 17 00:00:00 2001 From: adhinaik13 <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 20:40:30 +0530 Subject: [PATCH 08/43] docs: record final release verification evidence --- docs/integrations.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/integrations.md b/docs/integrations.md index 2b40a09..faed160 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -16,6 +16,8 @@ The upload was verified in GitHub Actions run [40882641655](https://github.com/v Keep the token only in GitHub Actions secrets; never commit it or paste it into source files, issues, or chat. Because the token appeared in a screenshot shared during setup, rotate/regenerate it in Codecov and replace the `CODECOV_TOKEN` repository secret with the new value. Then rerun CI to verify the rotated token works. Official guidance: https://github.com/codecov/codecov-action +The final PR check on commit `81b567b413a744044528af75d19d6772d19194aa` also passed Codecov's patch check: [Codecov patch check](https://github.com/vankudothuadhinaik/FluxQueue/runs/123521397956). This proves the upload/check succeeded, but does not prove that the exposed credential was rotated; that remains an account-owner action unless the replacement is separately verified. + ## Doppler The root `doppler.yaml` maps this repository to the Doppler project `fluxqueue`, config `dev`. The mapping is intentionally the same in every setup instruction. It is only a local CLI mapping; it does not create the project/config or prove the workspace is connected. @@ -79,15 +81,19 @@ Official references: - [CodeScene GitHub hosting integration](https://www.codescene.io/docs/providers/index.html) - [CodeScene Access vs. Delta Analysis](https://helpcenter.codescene.com/articles/9262058-codescene-access-vs-codescene-delta-analysis-which-github-app-do) +## Controlled proxy-security verification + +FluxQueue does not implement an outbound proxy, URL fetcher, redirect follower, DNS resolver, or SSRF protection layer. The repository's Nginx file is an example inbound reverse-proxy configuration (`deploy/nginx/fluxqueue.conf.example`), not a proxy implementation under test. Therefore DNS rebinding, unsafe destinations, redirect handling, malformed upstream responses, and proxy timeout behavior are not applicable repository tests and must not be claimed as passed. The example should be reviewed and tested separately in an authorized disposable deployment before public exposure. + ## Copilot and Codex Copilot and Codex are development assistants, not runtime dependencies. Keep their changes subject to the same tests, linting, migration checks, security analysis, and review gates as any other contribution. Never place production credentials in prompts or generated files. ## Current integration status -- GitHub Actions: configured; latest PR CI run [40893582266](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40893582266) passed all four jobs on commit `e07cb29`. -- CodeQL and Python dependency audit: passed in the latest PR CI run above. +- GitHub Actions: configured; final PR CI run [40894751613](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40894751613) passed all four jobs on commit `81b567b413a744044528af75d19d6772d19194aa`. +- CodeQL and Python dependency audit: passed in the final PR CI run above ([security](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40894751613/job/123520688092), [dependency audit](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40894751613/job/123520688002)). - Codecov: coverage upload was accepted and queued for processing in run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655). The token exposed in the setup screenshot should be rotated and `CODECOV_TOKEN` updated; do not claim rotation is verified until a run succeeds with the replacement token. - Doppler: project/config injection was reported verified in the PR's local smoke test; CI validates service wiring without requiring a Doppler token. -- CodeScene: PR integration is active; the latest review on PR #17 passed all three quality gates ([result](https://codescene.io/projects/87037/delta/results/8191366)). +- CodeScene: PR integration is active; the final review on PR #17 passed ([CodeScene check](https://github.com/vankudothuadhinaik/FluxQueue/runs/123520649693), [analysis result](https://codescene.io/projects/87037/delta/results/8191366)). - Render/other deployment: no production service is created by these files. Deploying a public service requires a deliberate environment, database, and cost decision. From 8f4ba1d9abc940be4a08180a3db5c3b1c562d673 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 21:42:45 +0530 Subject: [PATCH 09/43] ci: upgrade CodeQL actions to v4 --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 247b6a7..8788254 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -153,13 +153,13 @@ jobs: security-events: write steps: - uses: actions/checkout@v4 - - uses: github/codeql-action/init@v3 + - uses: github/codeql-action/init@v4 with: languages: python queries: security-extended # Keep CI usable when GitHub code scanning is not enabled for this repository. # SARIF is retained as an artifact; enabling code scanning allows upload to Security alerts. - - uses: github/codeql-action/analyze@v3 + - uses: github/codeql-action/analyze@v4 with: upload: false output: results From 79380d7ab256134b6a37d45b43848fb9b0ea830e Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 21:43:20 +0530 Subject: [PATCH 10/43] ci: update actions for Node 24 runtime --- .github/workflows/ci.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8788254..5442e17 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,8 +24,8 @@ jobs: env: DATABASE_URL: sqlite:///./ci-test.db steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 with: python-version: "3.12" cache: pip @@ -44,7 +44,7 @@ jobs: run: pytest --cov=fluxqueue --cov-report=xml --junitxml=junit.xml - name: Archive test and coverage reports if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: fluxqueue-test-reports path: | @@ -113,8 +113,8 @@ jobs: DATABASE_URL: postgresql+psycopg://fluxqueue:fluxqueue@localhost:5432/fluxqueue FLUXQUEUE_POSTGRES_TEST_URL: postgresql+psycopg://fluxqueue:fluxqueue@localhost:5432/fluxqueue steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 with: python-version: "3.12" cache: pip @@ -125,7 +125,7 @@ jobs: run: pytest -q tests/test_postgres_integration.py --junitxml=postgres-junit.xml - name: Archive PostgreSQL integration report if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: fluxqueue-postgres-integration-report path: postgres-junit.xml @@ -135,8 +135,8 @@ jobs: dependency-audit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 with: python-version: "3.12" cache: pip @@ -152,7 +152,7 @@ jobs: contents: read security-events: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - uses: github/codeql-action/init@v4 with: languages: python @@ -165,7 +165,7 @@ jobs: output: results - name: Archive CodeQL SARIF results if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: fluxqueue-codeql-sarif path: results/*.sarif From 6967ba6da53149fa89b997261f1a4f39e5aa09df Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 22:09:58 +0530 Subject: [PATCH 11/43] security: harden example nginx TLS defaults --- deploy/nginx/fluxqueue.conf.example | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deploy/nginx/fluxqueue.conf.example b/deploy/nginx/fluxqueue.conf.example index 7c51784..dc5c857 100644 --- a/deploy/nginx/fluxqueue.conf.example +++ b/deploy/nginx/fluxqueue.conf.example @@ -10,10 +10,12 @@ upstream fluxqueue_api { server { listen 443 ssl; server_name fluxqueue.example.com; + server_tokens off; # Replace with certificates provisioned by your TLS/certificate manager. ssl_certificate /etc/letsencrypt/live/fluxqueue.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/fluxqueue.example.com/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; client_max_body_size 128k; add_header Strict-Transport-Security "max-age=31536000" always; From c8c1d9fa739000447dec66101b5f3940c087926d Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 22:18:50 +0530 Subject: [PATCH 12/43] docs: update README with current implementation and release status --- README.md | 53 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 3aa4fce..4ea8260 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A durable job-processing platform built with FastAPI, SQLAlchemy, and PostgreSQL. -> **Status: active foundation.** Tenant-scoped API authorization and a PostgreSQL-serialized active-job quota per tenant are implemented with regression tests. Production hardening still requires verified CI, edge rate limiting, fault-injection testing, benchmarks, and deployment review. +> **Current status (2026-10-29): Doppler integration and CI hardening are implemented on PR #17.** The latest verified CI run is [40913827101](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40913827101) for commit `6967ba6da53149fa89b997261f1a4f39e5aa09df`; test/build, PostgreSQL integration, dependency audit, and CodeQL jobs all passed. The PR remains open and unmerged. CI success does **not** mean production readiness: credential rotation, real proxy/TLS validation, backup restoration, operations monitoring, and load/soak testing remain unverified release gates. ## Current capabilities @@ -15,6 +15,8 @@ A durable job-processing platform built with FastAPI, SQLAlchemy, and PostgreSQL - Separate worker process with registered handlers: `echo`, `add_numbers`, and `uppercase`. - Lease expiry/reclaim, heartbeat renewal, stale-token fencing, bounded exponential retry, terminal `dead` state, and payload-free worker lifecycle logs. - Non-root API/worker container, baseline security response headers, loopback-bound local Compose ports, Alembic migrations, SQLite unit/API tests, PostgreSQL concurrency integration tests, container startup/auth smoke checks, Ruff, CodeQL, automated dependency auditing, Dependabot, and optional Codecov. +- Doppler-to-Compose environment validation, secret-safe diagnostics, and URL-encoded PostgreSQL credentials. +- Example Nginx edge policy with explicit TLS 1.2/1.3 defaults, disabled server tokens, request-size limits, and per-IP API rate limiting. ## Quick start @@ -34,16 +36,20 @@ The worker polls the same PostgreSQL database and executes registered task types The Compose database password is a local-development default. Set `POSTGRES_PASSWORD` before shared use. For local development, `API_KEY` is optional. For production, set `APP_ENV=production` and configure `API_KEYS` as a JSON object mapping each high-entropy bearer key to a tenant identifier, for example `{"replace-with-a-long-random-secret":"tenant-a"}`. Send the key as `Authorization: Bearer `. The legacy `API_KEY` setting is retained for single-tenant deployments and maps to the `default` tenant; it does not provide tenant isolation by itself. When `API_KEYS` is non-empty, it takes precedence and the legacy key is not accepted. Store keys in Doppler or another secret manager, never in committed files. -For Doppler-backed Compose startup, configure project `fluxqueue`, config `dev`, and at least `POSTGRES_PASSWORD`, `APP_ENV`, `API_KEYS`, and optionally `MAX_ACTIVE_JOBS_PER_TENANT` in that config. From the repository root, authenticate with `doppler login`, then run `doppler setup --no-interactive` and verify without printing secret values: +### Doppler-backed Compose startup + +Configure Doppler project `fluxqueue`, config `dev`, and at least `POSTGRES_PASSWORD`, `APP_ENV`, and `API_KEYS`; `MAX_ACTIVE_JOBS_PER_TENANT` is optional. Authenticate using the Doppler CLI, then run from the repository root: ```bash +doppler login +doppler setup --no-interactive doppler run -- python scripts/validate_doppler_config.py --require-doppler-env doppler run -- docker compose up --build -d curl --fail http://127.0.0.1:8000/health/ready docker compose ps ``` -The API and worker receive the same resolved database/application environment, while PostgreSQL receives `POSTGRES_PASSWORD`. The validator checks this wiring and emits only variable names and safe diagnostics. +The API and worker receive the same resolved database/application environment, while PostgreSQL receives `POSTGRES_PASSWORD`. The validator checks this wiring and emits only variable names and safe diagnostics. Do not print or commit secret values. ## API @@ -113,18 +119,13 @@ ruff check . ruff format --check . ``` -The PostgreSQL-only integration tests verify real row-lock skipping, simultaneous worker claims, -expired lease reclamation, and stale-token fencing. They are run automatically by the -`postgres-integration` GitHub Actions job against a disposable PostgreSQL 16 service. To run -them locally, start a disposable PostgreSQL database and set -`FLUXQUEUE_POSTGRES_TEST_URL=postgresql+psycopg://USER:PASSWORD@HOST:5432/DATABASE`, then run: +The PostgreSQL-only integration tests verify real row-lock skipping, simultaneous worker claims, expired lease reclamation, and stale-token fencing. They run automatically in the `postgres-integration` GitHub Actions job against a disposable PostgreSQL 16 service. To run locally, start a disposable PostgreSQL database and set `FLUXQUEUE_POSTGRES_TEST_URL=postgresql+psycopg://USER:PASSWORD@HOST:5432/DATABASE`, then run: ```bash pytest -q tests/test_postgres_integration.py ``` -Do not point these integration tests at a database containing data you need to keep: the fixture -creates and drops the FluxQueue tables. +Do not point these integration tests at a database containing data you need to keep: the fixture creates and drops the FluxQueue tables. ## Benchmarking @@ -141,17 +142,39 @@ It reports request throughput, mean/p50/p95/p99 response latency, and HTTP statu The `0002_tenant_isolation` migration assigns existing jobs to the `default` tenant, adds tenant-scoped idempotency uniqueness, and indexes tenant queue queries. The worker uses lease tokens to fence stale completion/failure writes and renews leases while a handler runs. Expired claims can be reclaimed. Execution is at-least-once: an external side effect may occur before a worker crashes and acknowledges it, so side-effecting handlers must be idempotent. SQLite is useful for local development; use PostgreSQL for multi-worker deployments and concurrency behavior. -Tenant scope is derived exclusively from the authenticated API key, never from client-supplied request data. The `0002_tenant_isolation` migration backfills existing jobs into the `default` tenant and scopes idempotency keys by tenant and queue. Edge rate limiting, key rotation/revocation, process-kill/database-outage fault injection, production secret management, and controlled load/soak benchmark evidence remain release gates; a repeatable enqueue benchmark utility is included. `MAX_ACTIVE_JOBS_PER_TENANT` limits queued, running, and retry-wait jobs per tenant (default 1000); PostgreSQL advisory locks serialize quota checks across API replicas. See [deployment readiness](docs/deployment-readiness.md) for the pre-deployment checklist and required release evidence. See the [controlled fault-injection and soak-test runbook](docs/fault-injection-and-soak-test.md) for repeatable recovery and load-test procedures. CI includes a SQLite regression test that upgrades a populated pre-tenant jobs table, checks that existing job data survives with the `default` tenant, and verifies downgrade restoration. Migration upgrade/downgrade checks and PostgreSQL row-locking integration tests must pass on the newest run before release. +Tenant scope is derived exclusively from the authenticated API key, never from client-supplied request data. `MAX_ACTIVE_JOBS_PER_TENANT` limits queued, running, and retry-wait jobs per tenant (default 1000); PostgreSQL advisory locks serialize quota checks across API replicas. See [deployment readiness](docs/deployment-readiness.md) for the pre-deployment checklist and required release evidence, [controlled fault-injection and soak-test runbook](docs/fault-injection-and-soak-test.md) for recovery/load-test procedures, and [operations runbook](docs/operations.md) for key rotation, quotas, edge policy, recovery, and benchmarking. ## Integrations -See [developer tooling and integrations](docs/integrations.md) for GitHub Actions, Codecov, Doppler, CodeScene, Copilot, and Codex setup and verification boundaries. See the [operations runbook](docs/operations.md) for key rotation, quotas, edge policy, recovery, and benchmarking. +See [developer tooling and integrations](docs/integrations.md) for GitHub Actions, Codecov, Doppler, CodeScene, Copilot, and Codex setup and verification boundaries. + +Codecov upload activates when the repository Actions secret `CODECOV_TOKEN` is configured. A successful upload does not prove an exposed credential was revoked; confirm rotation and revocation in Codecov/GitHub settings. Doppler tokens must be supplied through a secret manager, never committed. CodeScene must be configured through its service UI. Documentation alone does not prove an integration is active. + +## CI status and latest verification + +CI runs on pushes, pull requests, and a weekly schedule. The latest verified run for this PR is [run 40913827101](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40913827101), associated with commit `6967ba6da53149fa89b997261f1a4f39e5aa09df`. All four jobs passed: + +- `test`: compilation, fresh/upgrade migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, container build/non-root check, protected-route smoke test, and Codecov upload. +- `postgres-integration`: PostgreSQL migration, locking, and lease-fencing checks. +- `dependency-audit`: resolved Python dependency audit. +- `security`: CodeQL analysis. + +Earlier verification recorded 68 passed and 4 skipped, plus 4 PostgreSQL integration tests passed and an authenticated Doppler development smoke test. These earlier results should not be misrepresented as fresh local execution of the latest commit. + +## Production readiness: still outstanding -Codecov upload activates when the repository Actions secret `CODECOV_TOKEN` is configured. Doppler tokens must be supplied through a secret manager, never committed. CodeScene must be configured through its service UI. Configuration in documentation alone does not prove that an integration is active. +**Do not treat this repository as production-ready solely because CI passes.** The following have not been verified against a real production-like deployment: -## CI status +- Revoke/rotate the previously exposed Codecov credential, update the GitHub Actions secret, and confirm the replacement works. +- Validate Nginx syntax, certificates, TLS negotiation, and proxy behavior in an authorized disposable environment. The example is a starting point; `limit_req_zone` belongs in the Nginx `http {}` context. +- Verify managed PostgreSQL TLS, network restrictions, least-privilege credentials, backup restoration, and migration rollback against production-like data. +- Exercise database outages, worker termination during handlers, lease expiry, retry exhaustion, and restart recovery. +- Verify idempotency for every external side-effecting handler. +- Add/verify operational metrics, structured logs, alerts, on-call ownership, resource limits, log retention, and rollback procedures. +- Run controlled load and soak tests; record throughput, latency percentiles, worker concurrency, and database utilization. +- Implement and test API-key rotation/revocation workflow; self-service key management is not implemented. -CI runs automatically on pushes, pull requests, and a weekly schedule. It checks SQLite unit/API tests, validates Compose configuration, builds the container and verifies it runs as non-root, smoke-tests startup/health/authenticated access, archives machine-readable test reports, audits resolved Python dependencies, and runs a separate PostgreSQL service job for `SKIP LOCKED`, concurrent claims, expired-lease recovery, and stale-token fencing. The PostgreSQL job also validates the Alembic migration. Treat a release as blocked unless the latest required CI checks pass; use GitHub's native check status and uploaded test reports as evidence, not screenshots or copied logs. Codecov upload is skipped unless `CODECOV_TOKEN` is configured. +Track and record evidence in [deployment readiness](docs/deployment-readiness.md). The PR remains open and unmerged pending owner decisions and release gates. ## License From 93418764a8300fee54f59a9d210cbf6bddf23b89 Mon Sep 17 00:00:00 2001 From: adhinaik13 <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 23:01:26 +0530 Subject: [PATCH 13/43] feat: harden production operations and observability --- .env.example | 6 +++ README.md | 5 +- compose.yaml | 4 ++ deploy/nginx/fluxqueue.conf.example | 6 +++ docs/deployment-readiness.md | 4 +- docs/failure-model.md | 3 +- docs/operations.md | 30 ++++++++++++ src/fluxqueue/config.py | 26 ++++++++++ src/fluxqueue/db.py | 6 +++ src/fluxqueue/main.py | 9 +++- src/fluxqueue/metrics.py | 73 +++++++++++++++++++++++++++++ src/fluxqueue/service.py | 2 + src/fluxqueue/worker.py | 25 ++++++++-- tests/test_api.py | 2 + tests/test_config.py | 31 ++++++++++++ tests/test_metrics.py | 29 ++++++++++++ 16 files changed, 251 insertions(+), 10 deletions(-) create mode 100644 src/fluxqueue/metrics.py create mode 100644 tests/test_metrics.py diff --git a/.env.example b/.env.example index 5329e23..c4cf41e 100644 --- a/.env.example +++ b/.env.example @@ -11,5 +11,11 @@ LOG_LEVEL=INFO API_KEY= API_KEYS={} MAX_ACTIVE_JOBS_PER_TENANT=1000 +# Managed PostgreSQL only: use verify-full or verify-ca in production and provision the CA file +# through the deployment environment. Never commit certificates or keys. +# DATABASE_SSLMODE=verify-full +# DATABASE_SSLROOTCERT=/run/secrets/postgres-ca.crt +# DATABASE_SSLCERT=/run/secrets/postgres-client.crt +# DATABASE_SSLKEY=/run/secrets/postgres-client.key # Example production mapping (store real keys only in Doppler or another secret manager): # API_KEYS={"replace-with-a-long-random-secret":"tenant-a"} diff --git a/README.md b/README.md index 3aa4fce..cb88bb2 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ A durable job-processing platform built with FastAPI, SQLAlchemy, and PostgreSQL - Job retrieval, filtering, pagination, queue counts, and cancellation. - Separate worker process with registered handlers: `echo`, `add_numbers`, and `uppercase`. - Lease expiry/reclaim, heartbeat renewal, stale-token fencing, bounded exponential retry, terminal `dead` state, and payload-free worker lifecycle logs. -- Non-root API/worker container, baseline security response headers, loopback-bound local Compose ports, Alembic migrations, SQLite unit/API tests, PostgreSQL concurrency integration tests, container startup/auth smoke checks, Ruff, CodeQL, automated dependency auditing, Dependabot, and optional Codecov. +- Non-root API/worker container, baseline security response headers, loopback-bound local Compose ports, Alembic migrations, SQLite unit/API tests, PostgreSQL concurrency integration tests, container startup/auth smoke checks, low-cardinality `/metrics`, Ruff, CodeQL, automated dependency auditing, Dependabot, and optional Codecov. ## Quick start @@ -45,6 +45,8 @@ docker compose ps The API and worker receive the same resolved database/application environment, while PostgreSQL receives `POSTGRES_PASSWORD`. The validator checks this wiring and emits only variable names and safe diagnostics. +For managed PostgreSQL, set `DATABASE_SSLMODE=verify-full` (preferred) or `verify-ca` and provide `DATABASE_SSLROOTCERT` through the secret/file provisioning system. Optional `DATABASE_SSLCERT` and `DATABASE_SSLKEY` support mutual TLS. Production configuration fails fast unless PostgreSQL is configured with certificate-verified TLS; local SQLite and development Compose remain available for development. + ## API - `POST /api/v1/jobs` @@ -53,6 +55,7 @@ The API and worker receive the same resolved database/application environment, w - `POST /api/v1/jobs/{job_id}/cancel` - `GET /api/v1/queues` - `GET /health/live` and `GET /health/ready` +- `GET /metrics` (keep this endpoint on a private monitoring network; it exposes aggregate counts, not payloads or credentials) ## Python SDK and CLI diff --git a/compose.yaml b/compose.yaml index ae823df..186bd24 100644 --- a/compose.yaml +++ b/compose.yaml @@ -5,6 +5,10 @@ x-fluxqueue-environment: &fluxqueue-environment API_KEY: ${API_KEY:-} API_KEYS: ${API_KEYS:-{}} MAX_ACTIVE_JOBS_PER_TENANT: ${MAX_ACTIVE_JOBS_PER_TENANT:-1000} + DATABASE_SSLMODE: ${DATABASE_SSLMODE:-} + DATABASE_SSLROOTCERT: ${DATABASE_SSLROOTCERT:-} + DATABASE_SSLCERT: ${DATABASE_SSLCERT:-} + DATABASE_SSLKEY: ${DATABASE_SSLKEY:-} services: db: diff --git a/deploy/nginx/fluxqueue.conf.example b/deploy/nginx/fluxqueue.conf.example index 7c51784..a42c606 100644 --- a/deploy/nginx/fluxqueue.conf.example +++ b/deploy/nginx/fluxqueue.conf.example @@ -10,13 +10,18 @@ upstream fluxqueue_api { server { listen 443 ssl; server_name fluxqueue.example.com; + server_tokens off; # Replace with certificates provisioned by your TLS/certificate manager. ssl_certificate /etc/letsencrypt/live/fluxqueue.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/fluxqueue.example.com/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; client_max_body_size 128k; add_header Strict-Transport-Security "max-age=31536000" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "DENY" always; + add_header Referrer-Policy "no-referrer" always; location /api/ { limit_req zone=fluxqueue_per_ip burst=20 nodelay; @@ -29,6 +34,7 @@ server { proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 5s; proxy_read_timeout 60s; + proxy_send_timeout 60s; proxy_pass http://fluxqueue_api; } diff --git a/docs/deployment-readiness.md b/docs/deployment-readiness.md index 25028bd..cd8cb01 100644 --- a/docs/deployment-readiness.md +++ b/docs/deployment-readiness.md @@ -21,8 +21,8 @@ FluxQueue is an early-stage job queue. Passing CI is necessary, but it does not - [ ] Define and test secret rotation and revocation without logging credentials. - [ ] Test database outage, worker termination during a handler, lease expiry, retry exhaustion, and recovery after restart. - [ ] Verify every external side-effecting handler is idempotent; execution is at-least-once, not exactly-once. -- [ ] Add structured logs and operational metrics for queue depth, oldest-job age, retries, dead jobs, lease expiry, handler duration, and database failures. -- [ ] Define alert thresholds, an on-call owner, backup restoration procedure, and a rollback procedure. +- [ ] Export `/metrics` to a private monitoring system and add structured aggregation for database failures and lease-expiry alerts; FluxQueue supplies low-cardinality queue, outcome, age, and processing-duration metrics but does not install an alert provider. +- [ ] Add alert thresholds, an on-call owner, backup restoration procedure, and a rollback procedure. - [ ] Run `scripts/benchmark_api.py` against a controlled environment, then run a separate end-to-end load/soak test; record throughput, latency percentiles, worker concurrency, and database utilization. - [ ] Review dependency/security scan results and resolve or explicitly accept findings. - [ ] Confirm migration rollout and rollback behavior against a disposable copy of production-like data; CI also tests tenant migration against a populated legacy SQLite table. diff --git a/docs/failure-model.md b/docs/failure-model.md index ab19d67..4b8edde 100644 --- a/docs/failure-model.md +++ b/docs/failure-model.md @@ -14,7 +14,8 @@ - Worker lifecycle logs record claims, outcomes, and stale-lease fencing without emitting job payloads or API keys. - Active jobs (queued, running, or waiting for retry) are capped per tenant by `MAX_ACTIVE_JOBS_PER_TENANT`; PostgreSQL advisory transaction locks serialize quota checks across API replicas. -The API/worker tests cover key transitions, but the full suite has not yet been confirmed green in GitHub Actions. +The API/worker tests cover key transitions; the final CI run must remain the release evidence for the +latest commit rather than relying on a local run. ## Delivery semantics diff --git a/docs/operations.md b/docs/operations.md index f2586f4..2f4fa49 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -42,6 +42,12 @@ and does not coordinate between multiple independent proxy instances; use a dist or shared rate-limit store for a multi-proxy deployment. Keep the application bound to a private network and do not trust client-supplied forwarded headers unless the trusted proxy overwrites them. +For managed PostgreSQL, set `DATABASE_SSLMODE=verify-full` and provide the CA bundle through +`DATABASE_SSLROOTCERT`. Use `verify-ca` only when hostname verification is intentionally handled +by the managed service's documented certificate policy. Do not use `require`, `prefer`, or an +unverified custom certificate in production. `DATABASE_SSLCERT` and `DATABASE_SSLKEY` are +available for mutual TLS and must be provisioned as protected files, not committed values. + ## Health and incident triage - /health/live indicates the API process is responding. @@ -49,6 +55,10 @@ network and do not trust client-supplied forwarded headers unless the trusted pr handling and investigation of PostgreSQL availability, connection limits, and credentials. - Worker logs include job ID, attempt count, state outcomes, and stale-lease rejection without logging job payloads or API keys. +- `/metrics` exposes fixed, low-cardinality counters for enqueued/completed/failed/retried/dead + jobs, current jobs by state, oldest queued-job age, and aggregate processing duration. Keep it + on a private monitoring network; no Prometheus server or alert provider is installed by this + repository. - Check queue counts and oldest queued-job age before increasing worker replicas. Review dead jobs, retry rates, handler duration, lease expiry, and database connection saturation. - Execution is at-least-once. For external side effects, use downstream idempotency keys and a @@ -64,6 +74,26 @@ network and do not trust client-supplied forwarded headers unless the trusted pr - Do not run the PostgreSQL integration tests against a database containing data you need to keep; their fixture creates and drops FluxQueue tables. +### Backup and restore procedure + +Recommended starting policy (not an established service commitment): daily full backups, point-in- +time recovery where the managed provider supports it, 35-day retention, an RPO target of 24 hours, +and an RTO target agreed with the service owner. Tighten these values only after measuring restore +time and storage cost. + +1. Create a fresh disposable PostgreSQL database or provider restore branch; never overwrite the + source database. +2. Restore the backup using the provider's documented tool, provision the same TLS CA and a + least-privilege application role, and run `alembic upgrade head`. +3. Verify representative job counts, tenant isolation, idempotency records, and `/health/ready` + against the restored target. +4. Record backup timestamp, migration revision, restore duration, validation results, and the + exact target identifier. Destroy the disposable target only after evidence is retained without + secrets. + +Migration rollback is not a disaster-recovery strategy. Prefer forward migrations or restore to a +new target, then switch traffic only after health and data checks pass. + ## Benchmarking Use scripts/benchmark_api.py only against a controlled environment you own. It measures enqueue diff --git a/src/fluxqueue/config.py b/src/fluxqueue/config.py index 8ab6304..cc9cbe3 100644 --- a/src/fluxqueue/config.py +++ b/src/fluxqueue/config.py @@ -21,6 +21,10 @@ class Settings(BaseSettings): database_port: int = 5432 database_name: str = "fluxqueue" database_user: str = "fluxqueue" + database_sslmode: str | None = None + database_sslrootcert: str | None = None + database_sslcert: str | None = None + database_sslkey: str | None = None log_level: str = "INFO" api_key: str | None = None api_keys: dict[str, str] = Field(default_factory=dict) @@ -36,6 +40,11 @@ def derive_database_url(self): f"@{self.database_host}:{self.database_port}/" f"{quote(self.database_name, safe='')}" ) + elif self.app_env.lower() in {"production", "prod"}: + raise ValueError( + "DATABASE_URL or POSTGRES_PASSWORD must be configured when " + "APP_ENV is production" + ) else: self.database_url = "sqlite:///./fluxqueue.db" return self @@ -49,6 +58,23 @@ def validate_authentication_settings(self): raise ValueError("API_KEYS must not contain empty API keys") if any(not tenant or len(tenant) > 128 for tenant in self.api_keys.values()): raise ValueError("API_KEYS tenant identifiers must be 1 to 128 characters") + if self.database_sslmode and self.database_sslmode not in { + "disable", + "allow", + "prefer", + "require", + "verify-ca", + "verify-full", + }: + raise ValueError("DATABASE_SSLMODE must be a supported PostgreSQL sslmode") + if ( + self.app_env.lower() in {"production", "prod"} + and not self.database_url.startswith("sqlite") + and self.database_sslmode not in {"verify-ca", "verify-full"} + ): + raise ValueError( + "production PostgreSQL requires DATABASE_SSLMODE=verify-ca or verify-full" + ) return self diff --git a/src/fluxqueue/db.py b/src/fluxqueue/db.py index b8362c7..f59d4ef 100644 --- a/src/fluxqueue/db.py +++ b/src/fluxqueue/db.py @@ -13,6 +13,12 @@ class Base(DeclarativeBase): connect_args = {"check_same_thread": False} if settings.database_url.startswith("sqlite") else {} +if settings.database_sslmode: + connect_args["sslmode"] = settings.database_sslmode +for name in ("sslrootcert", "sslcert", "sslkey"): + value = getattr(settings, f"database_{name}") + if value: + connect_args[name] = value engine = create_engine(settings.database_url, pool_pre_ping=True, connect_args=connect_args) SessionLocal = sessionmaker(bind=engine, autoflush=False, expire_on_commit=False) diff --git a/src/fluxqueue/main.py b/src/fluxqueue/main.py index 542710d..671f481 100644 --- a/src/fluxqueue/main.py +++ b/src/fluxqueue/main.py @@ -2,7 +2,7 @@ from fastapi import Depends, FastAPI, Header, Query from fastapi.exceptions import RequestValidationError -from fastapi.responses import JSONResponse +from fastapi.responses import JSONResponse, PlainTextResponse from sqlalchemy import func, select, text from sqlalchemy.orm import Session from starlette.middleware.base import RequestResponseEndpoint @@ -11,6 +11,7 @@ from fluxqueue.auth import require_api_key from fluxqueue.db import get_session +from fluxqueue.metrics import render from fluxqueue.models import Job from fluxqueue.schemas import JobCreate, JobList, JobRead from fluxqueue.service import cancel_queued_job, enqueue, get_job, list_jobs @@ -60,6 +61,12 @@ def ready(session: Session = Depends(get_session)) -> dict[str, str]: return {"status": "ready", "database": "reachable"} +@app.get("/metrics", response_class=PlainTextResponse, include_in_schema=False) +def metrics(session: Session = Depends(get_session)) -> PlainTextResponse: + """Expose low-cardinality operational metrics for a private scraper.""" + return PlainTextResponse(render(session), media_type="text/plain; version=0.0.4") + + @app.post( "/api/v1/jobs", response_model=JobRead, diff --git a/src/fluxqueue/metrics.py b/src/fluxqueue/metrics.py new file mode 100644 index 0000000..7582a74 --- /dev/null +++ b/src/fluxqueue/metrics.py @@ -0,0 +1,73 @@ +"""Low-cardinality process metrics for operational scraping.""" + +from __future__ import annotations + +from collections import Counter +from threading import Lock + +from sqlalchemy import func, select +from sqlalchemy.orm import Session + +from fluxqueue.models import Job, JobStatus + +_lock = Lock() +_counters: Counter[str] = Counter() +_durations: Counter[str] = Counter() + + +def increment(name: str, value: int = 1) -> None: + """Increment a fixed-name metric without accepting user-controlled labels.""" + with _lock: + _counters[name] += value + + +def observe_processing(seconds: float) -> None: + """Record processing duration using aggregate sum/count metrics.""" + with _lock: + _durations["count"] += 1 + _durations["sum"] += seconds + + +def _metric_value(name: str) -> int | float: + with _lock: + return _counters[name] + + +def render(session: Session) -> str: + """Render Prometheus text with fixed labels and current queue gauges.""" + counts = dict(session.execute(select(Job.status, func.count()).group_by(Job.status)).all()) + oldest_queued = session.scalar( + select(func.min(Job.created_at)).where(Job.status == JobStatus.QUEUED.value) + ) + lines = [ + "# HELP fluxqueue_jobs_total Jobs accepted by outcome.", + "# TYPE fluxqueue_jobs_total counter", + f'fluxqueue_jobs_total{{outcome="enqueued"}} {_metric_value("jobs_enqueued")}', + f'fluxqueue_jobs_total{{outcome="completed"}} {_metric_value("jobs_completed")}', + f'fluxqueue_jobs_total{{outcome="failed"}} {_metric_value("jobs_failed")}', + f'fluxqueue_jobs_total{{outcome="retried"}} {_metric_value("jobs_retried")}', + f'fluxqueue_jobs_total{{outcome="dead"}} {_metric_value("jobs_dead")}', + "# HELP fluxqueue_job_processing_seconds Job processing duration.", + "# TYPE fluxqueue_job_processing_seconds summary", + f"fluxqueue_job_processing_seconds_count {_durations['count']}", + f"fluxqueue_job_processing_seconds_sum {_durations['sum']:.6f}", + "# HELP fluxqueue_jobs Gauge of jobs by current state.", + "# TYPE fluxqueue_jobs gauge", + ] + for status in (status.value for status in JobStatus): + lines.append(f'fluxqueue_jobs{{status="{status}"}} {counts.get(status, 0)}') + oldest_age = 0.0 + if oldest_queued is not None: + from datetime import UTC, datetime + + if oldest_queued.tzinfo is None: + oldest_queued = oldest_queued.replace(tzinfo=UTC) + oldest_age = max(0.0, (datetime.now(UTC) - oldest_queued).total_seconds()) + lines.extend( + [ + "# HELP fluxqueue_oldest_queued_job_age_seconds Age of the oldest queued job.", + "# TYPE fluxqueue_oldest_queued_job_age_seconds gauge", + f"fluxqueue_oldest_queued_job_age_seconds {oldest_age:.6f}", + ] + ) + return "\n".join(lines) + "\n" diff --git a/src/fluxqueue/service.py b/src/fluxqueue/service.py index ee8ccd5..0135040 100644 --- a/src/fluxqueue/service.py +++ b/src/fluxqueue/service.py @@ -11,6 +11,7 @@ from sqlalchemy.orm import Session from fluxqueue.config import settings +from fluxqueue.metrics import increment from fluxqueue.models import Job, JobStatus from fluxqueue.schemas import JobCreate @@ -124,6 +125,7 @@ def enqueue( return existing raise HTTPException(status_code=409, detail="Conflicting idempotency key") from exc session.refresh(job) + increment("jobs_enqueued") return job diff --git a/src/fluxqueue/worker.py b/src/fluxqueue/worker.py index b74778a..f2c6228 100644 --- a/src/fluxqueue/worker.py +++ b/src/fluxqueue/worker.py @@ -15,6 +15,7 @@ from sqlalchemy.orm import Session from fluxqueue.db import SessionLocal +from fluxqueue.metrics import increment, observe_processing from fluxqueue.models import Job, JobStatus DEFAULT_LEASE_SECONDS = 60 @@ -262,6 +263,7 @@ def run_once(*, worker_id: str, lease_seconds: int = DEFAULT_LEASE_SECONDS) -> b daemon=True, ) heartbeat.start() + started = time.monotonic() try: handler = HANDLERS.get(job["task_type"]) if handler is None: @@ -270,6 +272,8 @@ def run_once(*, worker_id: str, lease_seconds: int = DEFAULT_LEASE_SECONDS) -> b with SessionLocal() as session: completed = complete_job(session, job["id"], job["lease_token"], result) if completed: + increment("jobs_completed") + observe_processing(time.monotonic() - started) logger.info("Job %s completed successfully", job["id"]) else: logger.warning( @@ -285,6 +289,9 @@ def run_once(*, worker_id: str, lease_seconds: int = DEFAULT_LEASE_SECONDS) -> b f"{type(exc).__name__}: {exc}", ) if state is not None: + increment("jobs_failed") + increment("jobs_dead" if state == JobStatus.DEAD.value else "jobs_retried") + observe_processing(time.monotonic() - started) logger.warning( "Job %s failed with %s; next state is %s", job["id"], @@ -304,17 +311,25 @@ def run_once(*, worker_id: str, lease_seconds: int = DEFAULT_LEASE_SECONDS) -> b def main() -> None: """Poll until interrupted; each worker has a unique lease identity.""" + import signal + worker_id = f"{socket.gethostname()}:{os.getpid()}:{uuid4().hex[:8]}" poll_seconds = 1.0 - while True: + shutdown = Event() + + def request_shutdown(signum: int, _frame: Any) -> None: + logger.info("Worker shutdown requested by signal %s", signum) + shutdown.set() + + signal.signal(signal.SIGTERM, request_shutdown) + signal.signal(signal.SIGINT, request_shutdown) + while not shutdown.is_set(): try: if not run_once(worker_id=worker_id): - time.sleep(poll_seconds) - except KeyboardInterrupt: - break + shutdown.wait(poll_seconds) except Exception: # A transient database failure should not kill the worker process. - time.sleep(min(10.0, poll_seconds * 2)) + shutdown.wait(min(10.0, poll_seconds * 2)) if __name__ == "__main__": diff --git a/tests/test_api.py b/tests/test_api.py index 5a5981c..e2a074a 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -223,6 +223,8 @@ def test_production_settings_accept_tenant_api_keys(): configured = Settings( app_env="production", + database_url="postgresql+psycopg://db.example/fluxqueue", + database_sslmode="verify-full", api_key=None, api_keys={"tenant-a-secret": "tenant-a"}, ) diff --git a/tests/test_config.py b/tests/test_config.py index 597045c..be5c856 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -21,3 +21,34 @@ def test_explicit_database_url_takes_precedence_over_compose_components(): ) assert configured.database_url == "postgresql+psycopg://external.example/fluxqueue" + + +def test_production_requires_a_database_configuration(): + import pytest + from pydantic import ValidationError + + with pytest.raises(ValidationError, match="DATABASE_URL or POSTGRES_PASSWORD"): + Settings(app_env="production", api_key="test-key") + + +def test_production_postgres_requires_certificate_verified_tls(): + import pytest + from pydantic import ValidationError + + with pytest.raises(ValidationError, match="DATABASE_SSLMODE"): + Settings( + app_env="production", + database_url="postgresql+psycopg://db.example/fluxqueue", + api_key="test-key", + ) + + +def test_configuration_errors_do_not_echo_secret_values(): + import pytest + from pydantic import ValidationError + + secret = "do-not-echo-this-secret" + with pytest.raises(ValidationError) as error: + Settings(api_keys={secret: ""}) + + assert secret not in str(error.value) diff --git a/tests/test_metrics.py b/tests/test_metrics.py new file mode 100644 index 0000000..e14958b --- /dev/null +++ b/tests/test_metrics.py @@ -0,0 +1,29 @@ +"""Operational metrics remain low-cardinality and secret-free.""" + +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker + +from fluxqueue.db import Base +from fluxqueue.metrics import render + + +def test_metrics_endpoint_exposes_safe_fixed_names(client): + response = client.get("/metrics") + + assert response.status_code == 200 + assert response.headers["content-type"].startswith("text/plain") + assert "fluxqueue_jobs_total" in response.text + assert "fluxqueue_oldest_queued_job_age_seconds" in response.text + assert "Authorization" not in response.text + + +def test_metrics_render_handles_sqlite_naive_timestamps(): + engine = create_engine("sqlite://") + Base.metadata.create_all(engine) + try: + session = sessionmaker(bind=engine)() + assert "fluxqueue_jobs" in render(session) + session.close() + finally: + Base.metadata.drop_all(engine) + engine.dispose() From 87bfda6b113c8869e60e760ea576d206c2772203 Mon Sep 17 00:00:00 2001 From: adhinaik13 <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 23:05:18 +0530 Subject: [PATCH 14/43] refactor: reduce enqueue complexity --- src/fluxqueue/service.py | 89 ++++++++++++++++++++-------------------- tests/test_config.py | 4 +- 2 files changed, 48 insertions(+), 45 deletions(-) diff --git a/src/fluxqueue/service.py b/src/fluxqueue/service.py index 0135040..c873d2e 100644 --- a/src/fluxqueue/service.py +++ b/src/fluxqueue/service.py @@ -21,57 +21,36 @@ class JobPage(NamedTuple): total: int -def fingerprint(data: JobCreate) -> str: - canonical = json.dumps(data.model_dump(mode="json"), sort_keys=True, separators=(",", ":")) - return hashlib.sha256(canonical.encode("utf-8")).hexdigest() - - -def enqueue( +def _find_idempotent_job( session: Session, data: JobCreate, idempotency_key: str | None, - tenant_id: str = "default", -) -> Job: - digest = fingerprint(data) - if idempotency_key: - existing = session.scalar( - select(Job).where( - Job.tenant_id == tenant_id, - Job.queue_name == data.queue, - Job.idempotency_key == idempotency_key, - ) + tenant_id: str, + digest: str, +) -> Job | None: + if not idempotency_key: + return None + existing = session.scalar( + select(Job).where( + Job.tenant_id == tenant_id, + Job.queue_name == data.queue, + Job.idempotency_key == idempotency_key, ) - if existing: - if existing.payload_fingerprint != digest: - raise HTTPException( - status_code=409, - detail="Idempotency key reused with different request", - ) - return existing + ) + if existing and existing.payload_fingerprint != digest: + raise HTTPException(status_code=409, detail="Idempotency key reused with different request") + return existing - # PostgreSQL advisory locks serialize quota checks for the same tenant across API replicas. + +def _lock_tenant(session: Session, tenant_id: str) -> None: if session.get_bind().dialect.name == "postgresql": session.execute( text("SELECT pg_advisory_xact_lock(hashtextextended(:tenant_id, 0))"), {"tenant_id": tenant_id}, ) - # Recheck idempotency after the lock: another replica may have committed while we waited. - if idempotency_key: - existing = session.scalar( - select(Job).where( - Job.tenant_id == tenant_id, - Job.queue_name == data.queue, - Job.idempotency_key == idempotency_key, - ) - ) - if existing: - if existing.payload_fingerprint != digest: - raise HTTPException( - status_code=409, - detail="Idempotency key reused with different request", - ) - return existing + +def _ensure_quota(session: Session, tenant_id: str) -> None: active_jobs = ( session.scalar( select(func.count()) @@ -91,10 +70,32 @@ def enqueue( ) if active_jobs >= settings.max_active_jobs_per_tenant: session.rollback() - raise HTTPException( - status_code=429, - detail="Tenant active job quota exceeded", - ) + raise HTTPException(status_code=429, detail="Tenant active job quota exceeded") + + +def fingerprint(data: JobCreate) -> str: + canonical = json.dumps(data.model_dump(mode="json"), sort_keys=True, separators=(",", ":")) + return hashlib.sha256(canonical.encode("utf-8")).hexdigest() + + +def enqueue( + session: Session, + data: JobCreate, + idempotency_key: str | None, + tenant_id: str = "default", +) -> Job: + digest = fingerprint(data) + existing = _find_idempotent_job(session, data, idempotency_key, tenant_id, digest) + if existing: + return existing + + # PostgreSQL advisory locks serialize quota checks for the same tenant across API replicas. + _lock_tenant(session, tenant_id) + # Recheck idempotency after the lock: another replica may have committed while we waited. + existing = _find_idempotent_job(session, data, idempotency_key, tenant_id, digest) + if existing: + return existing + _ensure_quota(session, tenant_id) now = datetime.now(UTC) job = Job( diff --git a/tests/test_config.py b/tests/test_config.py index be5c856..813c888 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -23,10 +23,12 @@ def test_explicit_database_url_takes_precedence_over_compose_components(): assert configured.database_url == "postgresql+psycopg://external.example/fluxqueue" -def test_production_requires_a_database_configuration(): +def test_production_requires_a_database_configuration(monkeypatch): import pytest from pydantic import ValidationError + monkeypatch.delenv("DATABASE_URL", raising=False) + monkeypatch.delenv("POSTGRES_PASSWORD", raising=False) with pytest.raises(ValidationError, match="DATABASE_URL or POSTGRES_PASSWORD"): Settings(app_env="production", api_key="test-key") From 96604cefc04b51d819e0da7faccc2460c570f136 Mon Sep 17 00:00:00 2001 From: adhinaik13 <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 23:06:53 +0530 Subject: [PATCH 15/43] docs: record final CI and integration verification --- README.md | 5 +++-- docs/integrations.md | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4be0be5..a802986 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A durable job-processing platform built with FastAPI, SQLAlchemy, and PostgreSQL. -> **Current status (2026-10-29): Doppler integration and CI hardening are implemented on PR #17.** The latest verified CI run is [40913827101](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40913827101) for commit `6967ba6da53149fa89b997261f1a4f39e5aa09df`; test/build, PostgreSQL integration, dependency audit, and CodeQL jobs all passed. The PR remains open and unmerged. CI success does **not** mean production readiness: credential rotation, real proxy/TLS validation, backup restoration, operations monitoring, and load/soak testing remain unverified release gates. +> **Current status (2026-10-29): Doppler integration and CI hardening are implemented on PR #17.** The latest verified CI run is [40922788784](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40922788784) for commit `87bfda6`; test/build, PostgreSQL integration, dependency audit, CodeQL, and CodeScene jobs all passed. The PR remains open and unmerged. CI success does **not** mean production readiness: credential rotation, real proxy/TLS validation, backup restoration, operations monitoring, and load/soak testing remain unverified release gates. ## Current capabilities @@ -155,12 +155,13 @@ Codecov upload activates when the repository Actions secret `CODECOV_TOKEN` is c ## CI status and latest verification -CI runs on pushes, pull requests, and a weekly schedule. The latest verified run for this PR is [run 40913827101](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40913827101), associated with commit `6967ba6da53149fa89b997261f1a4f39e5aa09df`. All four jobs passed: +CI runs on pushes, pull requests, and a weekly schedule. The latest verified run for this PR is [run 40922788784](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40922788784), associated with commit `87bfda6`. All four CI jobs and the CodeScene PR check passed: - `test`: compilation, fresh/upgrade migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, container build/non-root check, protected-route smoke test, and Codecov upload. - `postgres-integration`: PostgreSQL migration, locking, and lease-fencing checks. - `dependency-audit`: resolved Python dependency audit. - `security`: CodeQL analysis. +- `CodeScene Code Health Review (main)`: PR quality gates passed after reducing the `enqueue` hotspot complexity. Earlier verification recorded 68 passed and 4 skipped, plus 4 PostgreSQL integration tests passed and an authenticated Doppler development smoke test. These earlier results should not be misrepresented as fresh local execution of the latest commit. diff --git a/docs/integrations.md b/docs/integrations.md index faed160..e64bc77 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -74,7 +74,7 @@ CodeScene must be connected through its workspace and GitHub integration; do not If FluxQueue is not listed, check which GitHub account is connected to CodeScene and whether the CodeScene Access app installation includes this repository. Private repository analysis may depend on the CodeScene plan. Do not create a custom GitHub App or store a private key unless the CodeScene setup flow specifically requires it. -**Verification status (2026-10-29):** The FluxQueue project dashboard shows a successful analysis dated October 29, 2026, with average code health 9.4 and hotspot code health 9.6. The GitHub PR check is now verified: CodeScene posted `CodeScene Code Health Review (main)` on PR #17 and the latest review passed all three quality gates after the Doppler validator was refactored. See [latest CodeScene result](https://codescene.io/projects/87037/delta/results/8191366). +**Verification status (2026-10-29):** The FluxQueue project dashboard shows a successful analysis dated October 29, 2026. The GitHub PR check is verified: CodeScene posted `CodeScene Code Health Review (main)` on PR #17 and the latest review passed all three quality gates after the enqueue hotspot was simplified. See [latest CodeScene result](https://codescene.io/projects/87037/delta/results/8195097). Official references: - [CodeScene getting started](https://codescene.io/docs/getting-started/index.html) @@ -91,9 +91,9 @@ Copilot and Codex are development assistants, not runtime dependencies. Keep the ## Current integration status -- GitHub Actions: configured; final PR CI run [40894751613](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40894751613) passed all four jobs on commit `81b567b413a744044528af75d19d6772d19194aa`. -- CodeQL and Python dependency audit: passed in the final PR CI run above ([security](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40894751613/job/123520688092), [dependency audit](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40894751613/job/123520688002)). +- GitHub Actions: configured; final PR CI run [40922788784](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40922788784) passed all four jobs on commit `87bfda6`. +- CodeQL and Python dependency audit: passed in the final PR CI run above ([security](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40922788784/job/123620215952), [dependency audit](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40922788784/job/123620217165)). - Codecov: coverage upload was accepted and queued for processing in run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655). The token exposed in the setup screenshot should be rotated and `CODECOV_TOKEN` updated; do not claim rotation is verified until a run succeeds with the replacement token. -- Doppler: project/config injection was reported verified in the PR's local smoke test; CI validates service wiring without requiring a Doppler token. -- CodeScene: PR integration is active; the final review on PR #17 passed ([CodeScene check](https://github.com/vankudothuadhinaik/FluxQueue/runs/123520649693), [analysis result](https://codescene.io/projects/87037/delta/results/8191366)). +- Doppler: an authenticated local CLI check confirmed project `fluxqueue`, config `dev`, and secret injection; CI validates service wiring without requiring a Doppler token. +- CodeScene: PR integration is active; the final review on PR #17 passed ([CodeScene check](https://github.com/vankudothuadhinaik/FluxQueue/runs/123620182360), [analysis result](https://codescene.io/projects/87037/delta/results/8195097)). - Render/other deployment: no production service is created by these files. Deploying a public service requires a deliberate environment, database, and cost decision. From 1eeeff6b607d4426e399af0f07b8d942d316fc37 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 23:25:45 +0530 Subject: [PATCH 16/43] docs: refresh Codecov and CI verification evidence --- docs/integrations.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/integrations.md b/docs/integrations.md index e64bc77..1078fb7 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -14,9 +14,9 @@ The repository includes `.codecov.yml` and generates `coverage.xml` in GitHub Ac The upload was verified in GitHub Actions run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655): Codecov found `coverage.xml`, accepted the 3.6 KB upload, and reported **“Upload queued for processing complete.”** The report was queued for processing and can be viewed at the [Codecov commit report](https://app.codecov.io/github/vankudothuadhinaik/fluxqueue/commit/f5f6d93ee5212900ead0cfd9a79aa100d2ac91c5). -Keep the token only in GitHub Actions secrets; never commit it or paste it into source files, issues, or chat. Because the token appeared in a screenshot shared during setup, rotate/regenerate it in Codecov and replace the `CODECOV_TOKEN` repository secret with the new value. Then rerun CI to verify the rotated token works. Official guidance: https://github.com/codecov/codecov-action +Keep the token only in GitHub Actions secrets; never commit it or paste it into source files, issues, or chat. The repository owner reports that `CODECOV_TOKEN` has been updated in GitHub repository secrets. The test job was rerun on commit `96604cefc04b51d819e0da7faccc2460c570f136`, and the `Upload coverage to Codecov` step completed successfully in run [40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906). This verifies that the configured secret permits the upload; it does not independently prove the old credential was revoked in Codecov, so confirm revocation in the Codecov account if not already done. Official guidance: https://github.com/codecov/codecov-action -The final PR check on commit `81b567b413a744044528af75d19d6772d19194aa` also passed Codecov's patch check: [Codecov patch check](https://github.com/vankudothuadhinaik/FluxQueue/runs/123521397956). This proves the upload/check succeeded, but does not prove that the exposed credential was rotated; that remains an account-owner action unless the replacement is separately verified. +The latest Codecov upload step passed on commit `96604cefc04b51d819e0da7faccc2460c570f136` in [CI run 40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906). The repository owner reports the GitHub `CODECOV_TOKEN` secret was updated. This CI evidence confirms the configured secret works for upload; revocation of the previously exposed token must be confirmed in Codecov itself. ## Doppler @@ -91,9 +91,9 @@ Copilot and Codex are development assistants, not runtime dependencies. Keep the ## Current integration status -- GitHub Actions: configured; final PR CI run [40922788784](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40922788784) passed all four jobs on commit `87bfda6`. -- CodeQL and Python dependency audit: passed in the final PR CI run above ([security](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40922788784/job/123620215952), [dependency audit](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40922788784/job/123620217165)). -- Codecov: coverage upload was accepted and queued for processing in run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655). The token exposed in the setup screenshot should be rotated and `CODECOV_TOKEN` updated; do not claim rotation is verified until a run succeeds with the replacement token. +- GitHub Actions: configured; latest PR CI run [40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906) passed all four jobs on commit `96604cefc04b51d819e0da7faccc2460c570f136`. +- CodeQL and Python dependency audit: passed in the latest PR CI run above. CodeQL SARIF is archived as an artifact; workflow success does not mean alerts were uploaded to GitHub code scanning because upload is disabled. +- Codecov: upload step passed in the latest CI run [40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906) after the repository owner reported updating `CODECOV_TOKEN`. Confirm the old token is revoked in Codecov itself. - Doppler: an authenticated local CLI check confirmed project `fluxqueue`, config `dev`, and secret injection; CI validates service wiring without requiring a Doppler token. - CodeScene: PR integration is active; the final review on PR #17 passed ([CodeScene check](https://github.com/vankudothuadhinaik/FluxQueue/runs/123620182360), [analysis result](https://codescene.io/projects/87037/delta/results/8195097)). - Render/other deployment: no production service is created by these files. Deploying a public service requires a deliberate environment, database, and cost decision. From ab303b1c3ea39299956b57355d5faa72a9be257b Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 23:26:08 +0530 Subject: [PATCH 17/43] docs: refresh latest CI status and release gates --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a802986..10e9d4d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A durable job-processing platform built with FastAPI, SQLAlchemy, and PostgreSQL. -> **Current status (2026-10-29): Doppler integration and CI hardening are implemented on PR #17.** The latest verified CI run is [40922788784](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40922788784) for commit `87bfda6`; test/build, PostgreSQL integration, dependency audit, CodeQL, and CodeScene jobs all passed. The PR remains open and unmerged. CI success does **not** mean production readiness: credential rotation, real proxy/TLS validation, backup restoration, operations monitoring, and load/soak testing remain unverified release gates. +> **Current status (2026-10-29): Doppler integration and CI hardening are implemented on PR #17.** Latest verified CI run: [40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906) on commit `96604ce`; all four jobs passed, including the Codecov upload step after the repository owner reported updating `CODECOV_TOKEN`. The PR remains open and unmerged. CI success does **not** mean production readiness: confirm revocation of the previously exposed Codecov token in Codecov, and complete real proxy/TLS validation, backup restoration, operations monitoring, and load/soak testing before public deployment. ## Current capabilities @@ -155,7 +155,7 @@ Codecov upload activates when the repository Actions secret `CODECOV_TOKEN` is c ## CI status and latest verification -CI runs on pushes, pull requests, and a weekly schedule. The latest verified run for this PR is [run 40922788784](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40922788784), associated with commit `87bfda6`. All four CI jobs and the CodeScene PR check passed: +CI runs on pushes, pull requests, and a weekly schedule. The latest verified CI run for PR #17 is [run 40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906), associated with commit `96604ce`. All four CI jobs passed, including the Codecov upload step. The CodeScene PR review also passed its quality gates: - `test`: compilation, fresh/upgrade migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, container build/non-root check, protected-route smoke test, and Codecov upload. - `postgres-integration`: PostgreSQL migration, locking, and lease-fencing checks. @@ -163,7 +163,7 @@ CI runs on pushes, pull requests, and a weekly schedule. The latest verified run - `security`: CodeQL analysis. - `CodeScene Code Health Review (main)`: PR quality gates passed after reducing the `enqueue` hotspot complexity. -Earlier verification recorded 68 passed and 4 skipped, plus 4 PostgreSQL integration tests passed and an authenticated Doppler development smoke test. These earlier results should not be misrepresented as fresh local execution of the latest commit. +Earlier local verification recorded 73 passed and 4 skipped, plus 4 PostgreSQL integration tests passed and an authenticated Doppler development smoke test. These local results are separate from the latest GitHub Actions evidence; do not describe them as freshly rerun locally. ## Production readiness: still outstanding From 9b02e300eb476c62b43dc9a1c90c01a8190db2f2 Mon Sep 17 00:00:00 2001 From: adhinaik13 <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 23:34:15 +0530 Subject: [PATCH 18/43] ci: fail fast on coverage upload errors --- .github/workflows/ci.yml | 6 ++---- README.md | 8 ++++---- docs/integrations.md | 8 ++++---- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5442e17..357726a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,7 +91,7 @@ jobs: with: files: coverage.xml token: ${{ secrets.CODECOV_TOKEN }} - fail_ci_if_error: false + fail_ci_if_error: true postgres-integration: runs-on: ubuntu-latest @@ -157,11 +157,9 @@ jobs: with: languages: python queries: security-extended - # Keep CI usable when GitHub code scanning is not enabled for this repository. - # SARIF is retained as an artifact; enabling code scanning allows upload to Security alerts. - uses: github/codeql-action/analyze@v4 with: - upload: false + upload: true output: results - name: Archive CodeQL SARIF results if: always() diff --git a/README.md b/README.md index 10e9d4d..0ed8d90 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A durable job-processing platform built with FastAPI, SQLAlchemy, and PostgreSQL. -> **Current status (2026-10-29): Doppler integration and CI hardening are implemented on PR #17.** Latest verified CI run: [40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906) on commit `96604ce`; all four jobs passed, including the Codecov upload step after the repository owner reported updating `CODECOV_TOKEN`. The PR remains open and unmerged. CI success does **not** mean production readiness: confirm revocation of the previously exposed Codecov token in Codecov, and complete real proxy/TLS validation, backup restoration, operations monitoring, and load/soak testing before public deployment. +> **Current status (2026-10-29): Doppler integration and CI hardening are implemented on PR #17.** The latest pre-hardening CI run is [40926045141](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40926045141) on commit `ab303b1`; core jobs passed, but Codecov processing failed with `Token required because branch is protected`. The workflow now fails on Codecov upload errors and attempts CodeQL publication. The PR remains open and unmerged pending a valid FluxQueue Codecov token and external production gates. ## Current capabilities @@ -155,12 +155,12 @@ Codecov upload activates when the repository Actions secret `CODECOV_TOKEN` is c ## CI status and latest verification -CI runs on pushes, pull requests, and a weekly schedule. The latest verified CI run for PR #17 is [run 40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906), associated with commit `96604ce`. All four CI jobs passed, including the Codecov upload step. The CodeScene PR review also passed its quality gates: +CI runs on pushes, pull requests, and a weekly schedule. The latest pre-hardening run for PR #17 is [run 40926045141](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40926045141), associated with commit `ab303b1`. Core jobs and CodeScene passed, but Codecov processing failed because the protected-branch upload did not accept the configured secret. The workflow now treats that failure as blocking and publishes CodeQL SARIF when supported: -- `test`: compilation, fresh/upgrade migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, container build/non-root check, protected-route smoke test, and Codecov upload. +- `test`: compilation, fresh/upgrade migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, container build/non-root check, protected-route smoke test, and fail-fast Codecov upload. - `postgres-integration`: PostgreSQL migration, locking, and lease-fencing checks. - `dependency-audit`: resolved Python dependency audit. -- `security`: CodeQL analysis. +- `security`: CodeQL analysis and SARIF publication attempt. - `CodeScene Code Health Review (main)`: PR quality gates passed after reducing the `enqueue` hotspot complexity. Earlier local verification recorded 73 passed and 4 skipped, plus 4 PostgreSQL integration tests passed and an authenticated Doppler development smoke test. These local results are separate from the latest GitHub Actions evidence; do not describe them as freshly rerun locally. diff --git a/docs/integrations.md b/docs/integrations.md index 1078fb7..7bdacac 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -16,7 +16,7 @@ The upload was verified in GitHub Actions run [40882641655](https://github.com/v Keep the token only in GitHub Actions secrets; never commit it or paste it into source files, issues, or chat. The repository owner reports that `CODECOV_TOKEN` has been updated in GitHub repository secrets. The test job was rerun on commit `96604cefc04b51d819e0da7faccc2460c570f136`, and the `Upload coverage to Codecov` step completed successfully in run [40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906). This verifies that the configured secret permits the upload; it does not independently prove the old credential was revoked in Codecov, so confirm revocation in the Codecov account if not already done. Official guidance: https://github.com/codecov/codecov-action -The latest Codecov upload step passed on commit `96604cefc04b51d819e0da7faccc2460c570f136` in [CI run 40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906). The repository owner reports the GitHub `CODECOV_TOKEN` secret was updated. This CI evidence confirms the configured secret works for upload; revocation of the previously exposed token must be confirmed in Codecov itself. +Codecov verification is **BLOCKED**. Run [40926045141](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40926045141) supplied a token, but Codecov rejected the protected-branch upload with `Token required because branch is protected`. Replace the GitHub `CODECOV_TOKEN` secret with the FluxQueue repository token and rerun CI. Revocation of the previously exposed token must also be confirmed in Codecov itself. ## Doppler @@ -91,9 +91,9 @@ Copilot and Codex are development assistants, not runtime dependencies. Keep the ## Current integration status -- GitHub Actions: configured; latest PR CI run [40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906) passed all four jobs on commit `96604cefc04b51d819e0da7faccc2460c570f136`. -- CodeQL and Python dependency audit: passed in the latest PR CI run above. CodeQL SARIF is archived as an artifact; workflow success does not mean alerts were uploaded to GitHub code scanning because upload is disabled. -- Codecov: upload step passed in the latest CI run [40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906) after the repository owner reported updating `CODECOV_TOKEN`. Confirm the old token is revoked in Codecov itself. +- GitHub Actions: latest pre-hardening PR CI run [40926045141](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40926045141) passed core jobs on commit `ab303b1`; Codecov processing was rejected as described above. +- CodeQL and Python dependency audit: passed in that run; the workflow now attempts CodeQL SARIF publication with `security-events: write`. +- Codecov: **BLOCKED** until the repository secret is replaced and a fresh upload reports successful processing. - Doppler: an authenticated local CLI check confirmed project `fluxqueue`, config `dev`, and secret injection; CI validates service wiring without requiring a Doppler token. - CodeScene: PR integration is active; the final review on PR #17 passed ([CodeScene check](https://github.com/vankudothuadhinaik/FluxQueue/runs/123620182360), [analysis result](https://codescene.io/projects/87037/delta/results/8195097)). - Render/other deployment: no production service is created by these files. Deploying a public service requires a deliberate environment, database, and cost decision. From 689096463857dea0b7de3b125cb3fe25a5377c69 Mon Sep 17 00:00:00 2001 From: adhinaik13 <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 23:35:44 +0530 Subject: [PATCH 19/43] docs: record blocked Codecov verification --- docs/integrations.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/integrations.md b/docs/integrations.md index 7bdacac..6c868b9 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -12,6 +12,8 @@ JUnit test results and coverage XML are uploaded as workflow artifacts when avai The repository includes `.codecov.yml` and generates `coverage.xml` in GitHub Actions. The workflow uses the official Codecov Action and authenticates with the repository Actions secret `CODECOV_TOKEN`. +**Current verification status: BLOCKED.** The historical upload evidence below predates the current check. The latest protected-branch upload supplied a token but Codecov rejected it as requiring a valid token; replace the secret with the FluxQueue repository token and rerun CI. + The upload was verified in GitHub Actions run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655): Codecov found `coverage.xml`, accepted the 3.6 KB upload, and reported **“Upload queued for processing complete.”** The report was queued for processing and can be viewed at the [Codecov commit report](https://app.codecov.io/github/vankudothuadhinaik/fluxqueue/commit/f5f6d93ee5212900ead0cfd9a79aa100d2ac91c5). Keep the token only in GitHub Actions secrets; never commit it or paste it into source files, issues, or chat. The repository owner reports that `CODECOV_TOKEN` has been updated in GitHub repository secrets. The test job was rerun on commit `96604cefc04b51d819e0da7faccc2460c570f136`, and the `Upload coverage to Codecov` step completed successfully in run [40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906). This verifies that the configured secret permits the upload; it does not independently prove the old credential was revoked in Codecov, so confirm revocation in the Codecov account if not already done. Official guidance: https://github.com/codecov/codecov-action From 26b09734003283035f9d942aafbe102fb95d45b5 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 23:40:03 +0530 Subject: [PATCH 20/43] docs: refresh current CI verification status --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ed8d90..309c8b7 100644 --- a/README.md +++ b/README.md @@ -155,7 +155,7 @@ Codecov upload activates when the repository Actions secret `CODECOV_TOKEN` is c ## CI status and latest verification -CI runs on pushes, pull requests, and a weekly schedule. The latest pre-hardening run for PR #17 is [run 40926045141](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40926045141), associated with commit `ab303b1`. Core jobs and CodeScene passed, but Codecov processing failed because the protected-branch upload did not accept the configured secret. The workflow now treats that failure as blocking and publishes CodeQL SARIF when supported: +CI runs on pushes, pull requests, and a weekly schedule. The latest run for PR #17 is [run 40927562025](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40927562025) on commit `6890964`. Core test and container checks, PostgreSQL integration, dependency audit, CodeQL analysis, and CodeScene pass, but Codecov fails because the protected-branch upload rejects the configured token. The workflow now treats that failure as blocking and publishes CodeQL SARIF when supported: - `test`: compilation, fresh/upgrade migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, container build/non-root check, protected-route smoke test, and fail-fast Codecov upload. - `postgres-integration`: PostgreSQL migration, locking, and lease-fencing checks. From 54a8e72e0a865050610bc0460cfbc579dd929278 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 23:40:05 +0530 Subject: [PATCH 21/43] docs: record current Codecov token rejection --- docs/integrations.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/integrations.md b/docs/integrations.md index 6c868b9..78c4055 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -16,9 +16,9 @@ The repository includes `.codecov.yml` and generates `coverage.xml` in GitHub Ac The upload was verified in GitHub Actions run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655): Codecov found `coverage.xml`, accepted the 3.6 KB upload, and reported **“Upload queued for processing complete.”** The report was queued for processing and can be viewed at the [Codecov commit report](https://app.codecov.io/github/vankudothuadhinaik/fluxqueue/commit/f5f6d93ee5212900ead0cfd9a79aa100d2ac91c5). -Keep the token only in GitHub Actions secrets; never commit it or paste it into source files, issues, or chat. The repository owner reports that `CODECOV_TOKEN` has been updated in GitHub repository secrets. The test job was rerun on commit `96604cefc04b51d819e0da7faccc2460c570f136`, and the `Upload coverage to Codecov` step completed successfully in run [40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906). This verifies that the configured secret permits the upload; it does not independently prove the old credential was revoked in Codecov, so confirm revocation in the Codecov account if not already done. Official guidance: https://github.com/codecov/codecov-action +Keep the token only in GitHub Actions secrets; never commit it or paste it into source files, issues, or chat. The repository owner reports that `CODECOV_TOKEN` has been updated in GitHub repository secrets. The test job succeeded on commit `96604cefc04b51d819e0da7faccc2460c570f136` in run [40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906), but that success did not persist for the current head/token configuration. On current head `6890964`, run [40927562025](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40927562025) found `coverage.xml` and supplied a 50-character token; Codecov then rejected the protected-branch upload with `Token required because branch is protected`. Replace the GitHub repository secret `CODECOV_TOKEN` with the repository upload token generated/copied from the FluxQueue project in Codecov. Confirm the previously exposed token is revoked in Codecov, then rerun CI. This connection cannot read or write repository secret values, so the credential replacement must be performed in GitHub repository Settings → Secrets and variables → Actions. Official guidance: https://github.com/codecov/codecov-action. -Codecov verification is **BLOCKED**. Run [40926045141](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40926045141) supplied a token, but Codecov rejected the protected-branch upload with `Token required because branch is protected`. Replace the GitHub `CODECOV_TOKEN` secret with the FluxQueue repository token and rerun CI. Revocation of the previously exposed token must also be confirmed in Codecov itself. +Codecov verification is **BLOCKED**. Current head `6890964`, run [40927562025](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40927562025), supplied a token but Codecov rejected the protected-branch upload with `Token required because branch is protected`. Replace the GitHub `CODECOV_TOKEN` secret with the FluxQueue repository token and rerun CI. Revocation of the previously exposed token must also be confirmed in Codecov itself. ## Doppler From 5252449411840aa77d5fcc7200cd3a272199a199 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Thu, 29 Oct 2026 23:40:31 +0530 Subject: [PATCH 22/43] docs: correct stale latest CI status --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 309c8b7..a88fa88 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A durable job-processing platform built with FastAPI, SQLAlchemy, and PostgreSQL. -> **Current status (2026-10-29): Doppler integration and CI hardening are implemented on PR #17.** The latest pre-hardening CI run is [40926045141](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40926045141) on commit `ab303b1`; core jobs passed, but Codecov processing failed with `Token required because branch is protected`. The workflow now fails on Codecov upload errors and attempts CodeQL publication. The PR remains open and unmerged pending a valid FluxQueue Codecov token and external production gates. +> **Current status (2026-10-29): Doppler integration and CI hardening are implemented on PR #17.** Current head `6890964`; [CI run 40927562025](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40927562025) passes application tests, container smoke, PostgreSQL integration, dependency audit, and CodeQL analysis, but fails at Codecov upload with `Token required because branch is protected`. Replace the GitHub Actions `CODECOV_TOKEN` with the FluxQueue repository upload token from Codecov, confirm revocation of the old exposed token, and rerun CI. The PR remains open and unmerged pending valid Codecov authentication and external production-readiness gates. ## Current capabilities From 38fabcc8ff6b2c162784bb26d2871539c103d61c Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:09:57 +0530 Subject: [PATCH 23/43] docs: update CI status after Codecov upload passes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a88fa88..e992917 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A durable job-processing platform built with FastAPI, SQLAlchemy, and PostgreSQL. -> **Current status (2026-10-29): Doppler integration and CI hardening are implemented on PR #17.** Current head `6890964`; [CI run 40927562025](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40927562025) passes application tests, container smoke, PostgreSQL integration, dependency audit, and CodeQL analysis, but fails at Codecov upload with `Token required because branch is protected`. Replace the GitHub Actions `CODECOV_TOKEN` with the FluxQueue repository upload token from Codecov, confirm revocation of the old exposed token, and rerun CI. The PR remains open and unmerged pending valid Codecov authentication and external production-readiness gates. +> **Current status (2026-10-30):** PR #17 on `feat/doppler-integration` has a successful CI rerun at [run 40928314514](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40928314514), head `5252449`. The test job including Codecov upload, PostgreSQL integration, dependency audit, and CodeQL security analysis all passed. Codecov authentication is currently working. The PR remains open and unmerged while the production-readiness gates below are verified; CI success alone does not establish production readiness. ## Current capabilities @@ -155,7 +155,7 @@ Codecov upload activates when the repository Actions secret `CODECOV_TOKEN` is c ## CI status and latest verification -CI runs on pushes, pull requests, and a weekly schedule. The latest run for PR #17 is [run 40927562025](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40927562025) on commit `6890964`. Core test and container checks, PostgreSQL integration, dependency audit, CodeQL analysis, and CodeScene pass, but Codecov fails because the protected-branch upload rejects the configured token. The workflow now treats that failure as blocking and publishes CodeQL SARIF when supported: +CI runs on pushes, pull requests, and a weekly schedule. The latest verified retry for PR #17 is [run 40928314514](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40928314514) on commit `5252449`. The test job including Codecov upload, PostgreSQL integration, dependency audit, and CodeQL security analysis all passed. Codecov upload is currently verified working: - `test`: compilation, fresh/upgrade migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, container build/non-root check, protected-route smoke test, and fail-fast Codecov upload. - `postgres-integration`: PostgreSQL migration, locking, and lease-fencing checks. From 2e029a6e5ea84afe3849e0b747589084d1bb5ab1 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:10:05 +0530 Subject: [PATCH 24/43] docs: record successful Codecov token rotation --- docs/integrations.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/integrations.md b/docs/integrations.md index 78c4055..8fcde4e 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -12,13 +12,13 @@ JUnit test results and coverage XML are uploaded as workflow artifacts when avai The repository includes `.codecov.yml` and generates `coverage.xml` in GitHub Actions. The workflow uses the official Codecov Action and authenticates with the repository Actions secret `CODECOV_TOKEN`. -**Current verification status: BLOCKED.** The historical upload evidence below predates the current check. The latest protected-branch upload supplied a token but Codecov rejected it as requiring a valid token; replace the secret with the FluxQueue repository token and rerun CI. +**Current verification status: PASS (2026-10-30).** GitHub Actions run [40928314514](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40928314514) successfully uploaded coverage after the repository upload token was regenerated and the GitHub Actions `CODECOV_TOKEN` secret was updated. Keep the token in GitHub Actions secrets only; never commit or paste it into logs, source, or documentation. The upload was verified in GitHub Actions run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655): Codecov found `coverage.xml`, accepted the 3.6 KB upload, and reported **“Upload queued for processing complete.”** The report was queued for processing and can be viewed at the [Codecov commit report](https://app.codecov.io/github/vankudothuadhinaik/fluxqueue/commit/f5f6d93ee5212900ead0cfd9a79aa100d2ac91c5). -Keep the token only in GitHub Actions secrets; never commit it or paste it into source files, issues, or chat. The repository owner reports that `CODECOV_TOKEN` has been updated in GitHub repository secrets. The test job succeeded on commit `96604cefc04b51d819e0da7faccc2460c570f136` in run [40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906), but that success did not persist for the current head/token configuration. On current head `6890964`, run [40927562025](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40927562025) found `coverage.xml` and supplied a 50-character token; Codecov then rejected the protected-branch upload with `Token required because branch is protected`. Replace the GitHub repository secret `CODECOV_TOKEN` with the repository upload token generated/copied from the FluxQueue project in Codecov. Confirm the previously exposed token is revoked in Codecov, then rerun CI. This connection cannot read or write repository secret values, so the credential replacement must be performed in GitHub repository Settings → Secrets and variables → Actions. Official guidance: https://github.com/codecov/codecov-action. +Keep the token only in GitHub Actions secrets; never commit it or paste it into source files, issues, or chat. The owner regenerated the Codecov repository upload token and updated the GitHub Actions secret. The successful upload in run [40928314514](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40928314514) confirms the current secret works. A token was visible in a screenshot during troubleshooting; the owner regenerated it afterward. Treat all previously shown tokens as revoked and do not expose the current token. GitHub secret values cannot be read back through the GitHub connection. Official guidance: https://github.com/codecov/codecov-action. -Codecov verification is **BLOCKED**. Current head `6890964`, run [40927562025](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40927562025), supplied a token but Codecov rejected the protected-branch upload with `Token required because branch is protected`. Replace the GitHub `CODECOV_TOKEN` secret with the FluxQueue repository token and rerun CI. Revocation of the previously exposed token must also be confirmed in Codecov itself. +Codecov verification is **PASS** on the latest successful retry, [run 40928314514](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40928314514). The protected-branch coverage upload completed successfully after token rotation. ## Doppler @@ -95,7 +95,7 @@ Copilot and Codex are development assistants, not runtime dependencies. Keep the - GitHub Actions: latest pre-hardening PR CI run [40926045141](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40926045141) passed core jobs on commit `ab303b1`; Codecov processing was rejected as described above. - CodeQL and Python dependency audit: passed in that run; the workflow now attempts CodeQL SARIF publication with `security-events: write`. -- Codecov: **BLOCKED** until the repository secret is replaced and a fresh upload reports successful processing. +- Codecov: **PASS** in [run 40928314514](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40928314514) after repository token rotation and secret update. - Doppler: an authenticated local CLI check confirmed project `fluxqueue`, config `dev`, and secret injection; CI validates service wiring without requiring a Doppler token. - CodeScene: PR integration is active; the final review on PR #17 passed ([CodeScene check](https://github.com/vankudothuadhinaik/FluxQueue/runs/123620182360), [analysis result](https://codescene.io/projects/87037/delta/results/8195097)). - Render/other deployment: no production service is created by these files. Deploying a public service requires a deliberate environment, database, and cost decision. From a91a747f6aa47eb386ad077a8c9b7ad8ce43c890 Mon Sep 17 00:00:00 2001 From: adhinaik13 <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:21:09 +0530 Subject: [PATCH 25/43] docs: add Docker-first staging closeout --- .dockerignore | 27 +++++++++++++++++++++++++++ README.md | 20 ++++++++++++++++++-- docs/deployment-readiness.md | 2 ++ docs/integrations.md | 19 ++++++++++++++++++- 4 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e2c29b0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,27 @@ +.git +.github +.venv +venv +env +__pycache__ +*.py[cod] +.pytest_cache +.ruff_cache +.mypy_cache +.coverage +coverage.xml +htmlcov +*.egg-info +build +dist +ci-test.db +fluxqueue.db +*.log +.env +.env.* +!.env.example +tests +scripts +docs +deploy +docker-compose.override.yml diff --git a/README.md b/README.md index 0ed8d90..cc1239d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A durable job-processing platform built with FastAPI, SQLAlchemy, and PostgreSQL. -> **Current status (2026-10-29): Doppler integration and CI hardening are implemented on PR #17.** The latest pre-hardening CI run is [40926045141](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40926045141) on commit `ab303b1`; core jobs passed, but Codecov processing failed with `Token required because branch is protected`. The workflow now fails on Codecov upload errors and attempts CodeQL publication. The PR remains open and unmerged pending a valid FluxQueue Codecov token and external production gates. +> **Current status (2026-10-30):** Docker-first local staging passed on the current application code. The latest CI run is [40927562025](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40927562025) for `6890964`; PostgreSQL, dependency audit, security, CodeQL publication, and CodeScene passed, while the test job correctly failed on Codecov token validation. The PR remains open and unmerged pending a valid FluxQueue Codecov token and external production gates. ## Current capabilities @@ -53,6 +53,22 @@ The API and worker receive the same resolved database/application environment, w For managed PostgreSQL, set `DATABASE_SSLMODE=verify-full` (preferred) or `verify-ca` and provide `DATABASE_SSLROOTCERT` through the secret/file provisioning system. Optional `DATABASE_SSLCERT` and `DATABASE_SSLKEY` support mutual TLS. Production configuration fails fast unless PostgreSQL is configured with certificate-verified TLS; local SQLite and development Compose remain available for development. +### Docker-first local staging smoke test + +Use an isolated Compose project and loopback port for disposable staging validation. The command below uses test-only credentials: + +```powershell +$env:FLUXQUEUE_API_PORT = "18005" +$env:POSTGRES_PASSWORD = "docker-staging-password" +$env:API_KEY = "docker-staging-test-key" +$env:APP_ENV = "development" +docker compose -p fluxqueue-staging up -d --build +curl.exe --fail http://127.0.0.1:18005/health/ready +docker compose -p fluxqueue-staging ps +``` + +Verify liveness/readiness, protected-route responses, a harmless authenticated job, `/metrics`, worker logs, and restart recovery. Stop only this isolated project with `docker compose -p fluxqueue-staging down`; this preserves the disposable `fluxqueue-staging_postgres_data` volume. The image excludes tests, docs, local environments, caches, and Git metadata through `.dockerignore` and runs as UID/GID `10001:10001`. + ## API - `POST /api/v1/jobs` @@ -155,7 +171,7 @@ Codecov upload activates when the repository Actions secret `CODECOV_TOKEN` is c ## CI status and latest verification -CI runs on pushes, pull requests, and a weekly schedule. The latest pre-hardening run for PR #17 is [run 40926045141](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40926045141), associated with commit `ab303b1`. Core jobs and CodeScene passed, but Codecov processing failed because the protected-branch upload did not accept the configured secret. The workflow now treats that failure as blocking and publishes CodeQL SARIF when supported: +CI runs on pushes, pull requests, and a weekly schedule. The latest run for PR #17 is [40927562025](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40927562025), associated with commit `6890964`. PostgreSQL, dependency audit, security, CodeQL publication, and CodeScene passed; the test job failed only at the now fail-fast Codecov upload because the protected-branch token was rejected: - `test`: compilation, fresh/upgrade migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, container build/non-root check, protected-route smoke test, and fail-fast Codecov upload. - `postgres-integration`: PostgreSQL migration, locking, and lease-fencing checks. diff --git a/docs/deployment-readiness.md b/docs/deployment-readiness.md index cd8cb01..9e9b854 100644 --- a/docs/deployment-readiness.md +++ b/docs/deployment-readiness.md @@ -2,6 +2,8 @@ FluxQueue is an early-stage job queue. Passing CI is necessary, but it does not make a deployment production-ready. Keep the service private until the required gates below are complete. +Local Docker-first staging evidence (2026-10-30): the isolated `fluxqueue-staging` Compose project built successfully, ran API/worker as UID/GID `10001:10001`, passed readiness/authentication/metrics checks, completed a harmless job, produced no test-secret log matches, and recovered a completed job after Compose restart. This is local evidence only; it is not a deployed staging or production validation. + ## Before any shared environment - [ ] Configure `API_KEYS` in the secret manager as a JSON mapping from high-entropy bearer keys to tenant IDs; use legacy `API_KEY` only for a single-tenant deployment. diff --git a/docs/integrations.md b/docs/integrations.md index 6c868b9..2e7873c 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -8,6 +8,23 @@ On pushes and pull requests, CI runs lint/format checks, migration validation, u JUnit test results and coverage XML are uploaded as workflow artifacts when available. Open the workflow run to inspect the machine-readable reports; screenshots are not part of the verification process. +## Docker-first local staging + +The repository has no configured cloud staging environment. Use the isolated Compose project `fluxqueue-staging` for zero-cost local staging checks: + +```powershell +$env:FLUXQUEUE_API_PORT = "18005" +$env:POSTGRES_PASSWORD = "docker-staging-password" +$env:API_KEY = "docker-staging-test-key" +$env:APP_ENV = "development" +docker compose -p fluxqueue-staging up -d --build +curl.exe --fail http://127.0.0.1:18005/health/ready +docker compose -p fluxqueue-staging ps +docker compose -p fluxqueue-staging down +``` + +The validated smoke path also checks missing/invalid authentication, harmless job completion, `/metrics`, worker logs for secret leakage, and recovery of a completed job after `docker compose -p fluxqueue-staging restart`. The `fluxqueue-staging_postgres_data` volume is intentionally preserved by `down`; use a separate disposable project and volume for destructive migration tests. + ## Codecov The repository includes `.codecov.yml` and generates `coverage.xml` in GitHub Actions. The workflow uses the official Codecov Action and authenticates with the repository Actions secret `CODECOV_TOKEN`. @@ -16,7 +33,7 @@ The repository includes `.codecov.yml` and generates `coverage.xml` in GitHub Ac The upload was verified in GitHub Actions run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655): Codecov found `coverage.xml`, accepted the 3.6 KB upload, and reported **“Upload queued for processing complete.”** The report was queued for processing and can be viewed at the [Codecov commit report](https://app.codecov.io/github/vankudothuadhinaik/fluxqueue/commit/f5f6d93ee5212900ead0cfd9a79aa100d2ac91c5). -Keep the token only in GitHub Actions secrets; never commit it or paste it into source files, issues, or chat. The repository owner reports that `CODECOV_TOKEN` has been updated in GitHub repository secrets. The test job was rerun on commit `96604cefc04b51d819e0da7faccc2460c570f136`, and the `Upload coverage to Codecov` step completed successfully in run [40923030906](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40923030906). This verifies that the configured secret permits the upload; it does not independently prove the old credential was revoked in Codecov, so confirm revocation in the Codecov account if not already done. Official guidance: https://github.com/codecov/codecov-action +Keep the token only in GitHub Actions secrets; never commit it or paste it into source files, issues, or chat. The configured repository secret is currently rejected for the protected-branch upload. Replace it with the FluxQueue repository token and rerun CI; this repository cannot inspect or change the secret value. Official guidance: https://github.com/codecov/codecov-action Codecov verification is **BLOCKED**. Run [40926045141](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40926045141) supplied a token, but Codecov rejected the protected-branch upload with `Token required because branch is protected`. Replace the GitHub `CODECOV_TOKEN` secret with the FluxQueue repository token and rerun CI. Revocation of the previously exposed token must also be confirmed in Codecov itself. From 3d848eac0afecb236d2559164753c69bab8014ee Mon Sep 17 00:00:00 2001 From: adhinaik13 <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:23:38 +0530 Subject: [PATCH 26/43] docs: record final Docker and CI verification --- README.md | 4 ++-- docs/integrations.md | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 8cb1a48..c1de95f 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A durable job-processing platform built with FastAPI, SQLAlchemy, and PostgreSQL. -> **Current status (2026-10-30):** PR #17 on `feat/doppler-integration` has a successful CI rerun at [run 40928314514](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40928314514), head `5252449`. The test job including Codecov upload, PostgreSQL integration, dependency audit, and CodeQL security analysis all passed. Codecov authentication is currently working. The PR remains open and unmerged while the production-readiness gates below are verified; CI success alone does not establish production readiness. +> **Current status (2026-10-30):** Docker-first local staging passed, and final CI for PR #17 passed at [run 40934791341](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40934791341), head `dcde57b`. Test, Codecov, PostgreSQL integration, dependency audit, CodeQL, and CodeScene all passed. The PR remains open and unmerged while production-readiness gates below are verified; CI success alone does not establish production readiness. ## Current capabilities @@ -171,7 +171,7 @@ Codecov upload activates when the repository Actions secret `CODECOV_TOKEN` is c ## CI status and latest verification -CI runs on pushes, pull requests, and a weekly schedule. The latest verified retry for PR #17 is [run 40928314514](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40928314514) on commit `5252449`. The test job including Codecov upload, PostgreSQL integration, dependency audit, and CodeQL security analysis all passed. Codecov upload is currently verified working: +CI runs on pushes, pull requests, and a weekly schedule. The latest verified run for PR #17 is [40934791341](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40934791341), associated with commit `dcde57b`. Test, Codecov, PostgreSQL integration, dependency audit, CodeQL publication, and CodeScene all passed: - `test`: compilation, fresh/upgrade migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, container build/non-root check, protected-route smoke test, and fail-fast Codecov upload. - `postgres-integration`: PostgreSQL migration, locking, and lease-fencing checks. diff --git a/docs/integrations.md b/docs/integrations.md index 4f6d4bc..da96a8d 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -29,13 +29,13 @@ The validated smoke path also checks missing/invalid authentication, harmless jo The repository includes `.codecov.yml` and generates `coverage.xml` in GitHub Actions. The workflow uses the official Codecov Action and authenticates with the repository Actions secret `CODECOV_TOKEN`. -**Current verification status: PASS (2026-10-30).** GitHub Actions run [40928314514](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40928314514) successfully uploaded coverage after the repository upload token was regenerated and the GitHub Actions `CODECOV_TOKEN` secret was updated. Keep the token in GitHub Actions secrets only; never commit or paste it into logs, source, or documentation. +**Current verification status: PASS (2026-10-30).** GitHub Actions run [40934791341](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40934791341) successfully uploaded coverage for commit `dcde57b` after the repository upload token was regenerated and the GitHub Actions `CODECOV_TOKEN` secret was updated. Keep the token in GitHub Actions secrets only; never commit or paste it into logs, source, or documentation. The upload was verified in GitHub Actions run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655): Codecov found `coverage.xml`, accepted the 3.6 KB upload, and reported **“Upload queued for processing complete.”** The report was queued for processing and can be viewed at the [Codecov commit report](https://app.codecov.io/github/vankudothuadhinaik/fluxqueue/commit/f5f6d93ee5212900ead0cfd9a79aa100d2ac91c5). Keep the token only in GitHub Actions secrets; never commit it or paste it into source files, issues, or chat. The owner regenerated the Codecov repository upload token and updated the GitHub Actions secret. The successful upload in run [40928314514](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40928314514) confirms the current secret works. A token was visible in a screenshot during troubleshooting; the owner regenerated it afterward. Treat all previously shown tokens as revoked and do not expose the current token. GitHub secret values cannot be read back through the GitHub connection. Official guidance: https://github.com/codecov/codecov-action. -Codecov verification is **PASS** on the latest successful retry, [run 40928314514](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40928314514). The protected-branch coverage upload completed successfully after token rotation. +Codecov verification is **PASS** on the final commit in [run 40934791341](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40934791341). The protected-branch coverage upload completed successfully after token rotation. ## Doppler @@ -110,9 +110,9 @@ Copilot and Codex are development assistants, not runtime dependencies. Keep the ## Current integration status -- GitHub Actions: latest pre-hardening PR CI run [40926045141](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40926045141) passed core jobs on commit `ab303b1`; Codecov processing was rejected as described above. -- CodeQL and Python dependency audit: passed in that run; the workflow now attempts CodeQL SARIF publication with `security-events: write`. -- Codecov: **PASS** in [run 40928314514](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40928314514) after repository token rotation and secret update. +- GitHub Actions: final PR CI run [40934791341](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40934791341) passed all jobs on commit `dcde57b`. +- CodeQL and Python dependency audit: passed in the final run; CodeQL SARIF publication succeeded. +- Codecov: **PASS** in [run 40934791341](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40934791341) after repository token rotation and secret update. - Doppler: an authenticated local CLI check confirmed project `fluxqueue`, config `dev`, and secret injection; CI validates service wiring without requiring a Doppler token. -- CodeScene: PR integration is active; the final review on PR #17 passed ([CodeScene check](https://github.com/vankudothuadhinaik/FluxQueue/runs/123620182360), [analysis result](https://codescene.io/projects/87037/delta/results/8195097)). +- CodeScene: PR integration is active; the final review on PR #17 passed ([CodeScene check](https://github.com/vankudothuadhinaik/FluxQueue/runs/123662321543), [analysis result](https://codescene.io/projects/87037/delta/results/8195097)). - Render/other deployment: no production service is created by these files. Deploying a public service requires a deliberate environment, database, and cost decision. From d59b0d2708ffdfb825083de03b7a793a43bb5024 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:34:18 +0530 Subject: [PATCH 27/43] docs: align final CI evidence with Docker closeout --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c1de95f..8b48b72 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A durable job-processing platform built with FastAPI, SQLAlchemy, and PostgreSQL. -> **Current status (2026-10-30):** Docker-first local staging passed, and final CI for PR #17 passed at [run 40934791341](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40934791341), head `dcde57b`. Test, Codecov, PostgreSQL integration, dependency audit, CodeQL, and CodeScene all passed. The PR remains open and unmerged while production-readiness gates below are verified; CI success alone does not establish production readiness. +> **Current status (2026-10-30):** Docker-first local staging passed, and final CI for PR #17 passed at [run 40935078574](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40935078574), head `3d848ea`. Test, Codecov, PostgreSQL integration, dependency audit, CodeQL, and CodeScene all passed. The PR remains open and unmerged while production-readiness gates below are verified; CI success alone does not establish production readiness. ## Current capabilities From 78f89b0bb0e6091e2b5346a6d4121a0e88428785 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:34:27 +0530 Subject: [PATCH 28/43] docs: align Codecov evidence with final staging CI --- docs/integrations.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/integrations.md b/docs/integrations.md index da96a8d..30ccced 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -29,13 +29,13 @@ The validated smoke path also checks missing/invalid authentication, harmless jo The repository includes `.codecov.yml` and generates `coverage.xml` in GitHub Actions. The workflow uses the official Codecov Action and authenticates with the repository Actions secret `CODECOV_TOKEN`. -**Current verification status: PASS (2026-10-30).** GitHub Actions run [40934791341](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40934791341) successfully uploaded coverage for commit `dcde57b` after the repository upload token was regenerated and the GitHub Actions `CODECOV_TOKEN` secret was updated. Keep the token in GitHub Actions secrets only; never commit or paste it into logs, source, or documentation. +**Current verification status: PASS (2026-10-30).** GitHub Actions run [40935078574](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40935078574) successfully uploaded coverage for final PR head `3d848ea` after the repository upload token was regenerated and the GitHub Actions `CODECOV_TOKEN` secret was updated. Keep the token in GitHub Actions secrets only; never commit or paste it into logs, source, or documentation. The upload was verified in GitHub Actions run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655): Codecov found `coverage.xml`, accepted the 3.6 KB upload, and reported **“Upload queued for processing complete.”** The report was queued for processing and can be viewed at the [Codecov commit report](https://app.codecov.io/github/vankudothuadhinaik/fluxqueue/commit/f5f6d93ee5212900ead0cfd9a79aa100d2ac91c5). Keep the token only in GitHub Actions secrets; never commit it or paste it into source files, issues, or chat. The owner regenerated the Codecov repository upload token and updated the GitHub Actions secret. The successful upload in run [40928314514](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40928314514) confirms the current secret works. A token was visible in a screenshot during troubleshooting; the owner regenerated it afterward. Treat all previously shown tokens as revoked and do not expose the current token. GitHub secret values cannot be read back through the GitHub connection. Official guidance: https://github.com/codecov/codecov-action. -Codecov verification is **PASS** on the final commit in [run 40934791341](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40934791341). The protected-branch coverage upload completed successfully after token rotation. +Codecov verification is **PASS** on the final commit in [run 40935078574](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40935078574). The protected-branch coverage upload completed successfully after token rotation. ## Doppler From 4ccf42362afed8aef27678e722fc68cdaae921f6 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:37:01 +0530 Subject: [PATCH 29/43] docs: clarify final CI status and production gates --- README.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8b48b72..94e1d9e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A durable job-processing platform built with FastAPI, SQLAlchemy, and PostgreSQL. -> **Current status (2026-10-30):** Docker-first local staging passed, and final CI for PR #17 passed at [run 40935078574](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40935078574), head `3d848ea`. Test, Codecov, PostgreSQL integration, dependency audit, CodeQL, and CodeScene all passed. The PR remains open and unmerged while production-readiness gates below are verified; CI success alone does not establish production readiness. +> **Current status (2026-10-30):** Docker-first local staging passed, and CI for PR #17 passed at [run 40936739361](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40936739361), head `78f89b0`. Test, PostgreSQL integration, dependency audit, and security jobs passed; Codecov upload is included in the test job. The PR remains open and unmerged. These results do not establish production readiness. ## Current capabilities @@ -171,31 +171,30 @@ Codecov upload activates when the repository Actions secret `CODECOV_TOKEN` is c ## CI status and latest verification -CI runs on pushes, pull requests, and a weekly schedule. The latest verified run for PR #17 is [40934791341](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40934791341), associated with commit `dcde57b`. Test, Codecov, PostgreSQL integration, dependency audit, CodeQL publication, and CodeScene all passed: +The latest verified CI run for PR #17 is [40936739361](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40936739361), for commit `78f89b0` on `feat/doppler-integration`. All four jobs passed: -- `test`: compilation, fresh/upgrade migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, container build/non-root check, protected-route smoke test, and fail-fast Codecov upload. +- `test`: compilation, migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, Docker build, non-root check, container smoke test, and Codecov upload. - `postgres-integration`: PostgreSQL migration, locking, and lease-fencing checks. - `dependency-audit`: resolved Python dependency audit. -- `security`: CodeQL analysis and SARIF publication attempt. -- `CodeScene Code Health Review (main)`: PR quality gates passed after reducing the `enqueue` hotspot complexity. +- `security`: CodeQL analysis and SARIF publication. -Earlier local verification recorded 73 passed and 4 skipped, plus 4 PostgreSQL integration tests passed and an authenticated Doppler development smoke test. These local results are separate from the latest GitHub Actions evidence; do not describe them as freshly rerun locally. +The Docker-first local staging run and its detailed checks are recorded above and in [developer tooling and integrations](docs/integrations.md). Earlier local verification recorded 73 passed and 4 skipped, plus 4 PostgreSQL integration tests passed; those local results are historical and are not claimed as freshly rerun during the final documentation update. ## Production readiness: still outstanding -**Do not treat this repository as production-ready solely because CI passes.** The following have not been verified against a real production-like deployment: +**CI and local Docker success do not make FluxQueue production-ready.** The following deployment-owner gates remain open: -- Revoke/rotate the previously exposed Codecov credential, update the GitHub Actions secret, and confirm the replacement works. +- Confirm Codecov credential rotation/revocation in provider settings; the replacement upload succeeded in CI, but secret values cannot be read back through GitHub. - Validate Nginx syntax, certificates, TLS negotiation, and proxy behavior in an authorized disposable environment. The example is a starting point; `limit_req_zone` belongs in the Nginx `http {}` context. - Verify managed PostgreSQL TLS, network restrictions, least-privilege credentials, backup restoration, and migration rollback against production-like data. - Exercise database outages, worker termination during handlers, lease expiry, retry exhaustion, and restart recovery. - Verify idempotency for every external side-effecting handler. -- Add/verify operational metrics, structured logs, alerts, on-call ownership, resource limits, log retention, and rollback procedures. +- Configure and verify operational metrics, structured logs, alerts, on-call ownership, resource limits, log retention, and rollback procedures. - Run controlled load and soak tests; record throughput, latency percentiles, worker concurrency, and database utilization. - Implement and test API-key rotation/revocation workflow; self-service key management is not implemented. -Track and record evidence in [deployment readiness](docs/deployment-readiness.md). The PR remains open and unmerged pending owner decisions and release gates. - +Track evidence in [deployment readiness](docs/deployment-readiness.md). No cloud staging environment has been provisioned, and PR #17 remains open and unmerged. + ## License MIT — see [LICENSE](LICENSE). From 375bd9917105b57ec931d3de31f2f1dc68681c66 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:37:07 +0530 Subject: [PATCH 30/43] docs: simplify Codecov verification record --- docs/integrations.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/integrations.md b/docs/integrations.md index 30ccced..22de595 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -27,15 +27,11 @@ The validated smoke path also checks missing/invalid authentication, harmless jo ## Codecov -The repository includes `.codecov.yml` and generates `coverage.xml` in GitHub Actions. The workflow uses the official Codecov Action and authenticates with the repository Actions secret `CODECOV_TOKEN`. +The repository includes `.codecov.yml` and generates `coverage.xml` in GitHub Actions. The workflow uses the official Codecov Action and reads the upload token from the repository Actions secret `CODECOV_TOKEN`. -**Current verification status: PASS (2026-10-30).** GitHub Actions run [40935078574](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40935078574) successfully uploaded coverage for final PR head `3d848ea` after the repository upload token was regenerated and the GitHub Actions `CODECOV_TOKEN` secret was updated. Keep the token in GitHub Actions secrets only; never commit or paste it into logs, source, or documentation. +**Verified:** the final documentation commit `78f89b0` passed CI in [run 40936739361](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40936739361), including the Codecov upload step. The earlier upload failure was resolved after the owner regenerated the repository upload token and updated the GitHub Actions secret. -The upload was verified in GitHub Actions run [40882641655](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40882641655): Codecov found `coverage.xml`, accepted the 3.6 KB upload, and reported **“Upload queued for processing complete.”** The report was queued for processing and can be viewed at the [Codecov commit report](https://app.codecov.io/github/vankudothuadhinaik/fluxqueue/commit/f5f6d93ee5212900ead0cfd9a79aa100d2ac91c5). - -Keep the token only in GitHub Actions secrets; never commit it or paste it into source files, issues, or chat. The owner regenerated the Codecov repository upload token and updated the GitHub Actions secret. The successful upload in run [40928314514](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40928314514) confirms the current secret works. A token was visible in a screenshot during troubleshooting; the owner regenerated it afterward. Treat all previously shown tokens as revoked and do not expose the current token. GitHub secret values cannot be read back through the GitHub connection. Official guidance: https://github.com/codecov/codecov-action. - -Codecov verification is **PASS** on the final commit in [run 40935078574](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40935078574). The protected-branch coverage upload completed successfully after token rotation. +Keep the token in GitHub Actions secrets only. Never commit, log, or paste secret values. A successful upload verifies the upload path works; it does not independently prove that any previously exposed credential has been revoked. Confirm revocation in Codecov/GitHub settings if that confirmation has not already been made. GitHub does not return stored secret values through the repository connection. ## Doppler From b5a42a39ec3d1861bdcae0187edb3346c295a27a Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:37:21 +0530 Subject: [PATCH 31/43] docs: align integration status with verified CI --- docs/integrations.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/integrations.md b/docs/integrations.md index 22de595..baa702b 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -106,9 +106,9 @@ Copilot and Codex are development assistants, not runtime dependencies. Keep the ## Current integration status -- GitHub Actions: final PR CI run [40934791341](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40934791341) passed all jobs on commit `dcde57b`. -- CodeQL and Python dependency audit: passed in the final run; CodeQL SARIF publication succeeded. -- Codecov: **PASS** in [run 40934791341](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40934791341) after repository token rotation and secret update. -- Doppler: an authenticated local CLI check confirmed project `fluxqueue`, config `dev`, and secret injection; CI validates service wiring without requiring a Doppler token. -- CodeScene: PR integration is active; the final review on PR #17 passed ([CodeScene check](https://github.com/vankudothuadhinaik/FluxQueue/runs/123662321543), [analysis result](https://codescene.io/projects/87037/delta/results/8195097)). -- Render/other deployment: no production service is created by these files. Deploying a public service requires a deliberate environment, database, and cost decision. +- GitHub Actions: latest verified PR CI run [40936739361](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40936739361) passed all four jobs on commit `78f89b0`. +- CodeQL and Python dependency audit: passed in that run; CodeQL analysis and SARIF publication completed. +- Codecov: coverage upload passed in the test job on the same run after the owner rotated the repository upload token and updated the Actions secret. Confirm revocation of any previously exposed token in provider settings; a successful replacement upload alone does not prove revocation. +- Doppler: a previously reported authenticated local CLI check confirmed project `fluxqueue`, config `dev`, and secret injection; CI validates service wiring without requiring a Doppler token. This is historical local evidence, not a fresh CLI run during the documentation closeout. +- CodeScene: the PR integration check and review passed on the closeout changes ([CodeScene check](https://github.com/vankudothuadhinaik/FluxQueue/runs/123662321543), [analysis result](https://codescene.io/projects/87037/delta/results/8195097)). +- Render/other deployment: no FluxQueue staging or production service was created. A deployment still requires an explicit environment, dedicated database, and cost decision. From 72292ae16413db7f4011d838f1644b7dac845e29 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:39:47 +0530 Subject: [PATCH 32/43] ci: validate example nginx configuration --- .github/workflows/ci.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 357726a..129ebac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,6 +86,20 @@ jobs: test "$(curl --silent --output /dev/null --write-out '%{http_code}' \ --header 'Authorization: Bearer ci-smoke-test-key' \ http://127.0.0.1:8000/api/v1/jobs)" = "200" + - name: Validate example Nginx configuration + shell: bash + run: | + set -euo pipefail + cert_dir="$(mktemp -d)" + trap 'rm -rf "$cert_dir"' EXIT + openssl req -x509 -nodes -newkey rsa:2048 -days 1 \ + -keyout "$cert_dir/privkey.pem" \ + -out "$cert_dir/fullchain.pem" \ + -subj "/CN=fluxqueue.example.com" >/dev/null 2>&1 + docker run --rm \ + --volume "$PWD/deploy/nginx/fluxqueue.conf.example:/etc/nginx/conf.d/fluxqueue.conf:ro" \ + --volume "$cert_dir:/etc/letsencrypt/live/fluxqueue.example.com:ro" \ + nginx:alpine nginx -t - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 with: From 407485269161ef8a2179f16511435c96ed9f05da Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:39:53 +0530 Subject: [PATCH 33/43] docs: document nginx syntax validation in CI --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 94e1d9e..65f7c54 100644 --- a/README.md +++ b/README.md @@ -173,7 +173,7 @@ Codecov upload activates when the repository Actions secret `CODECOV_TOKEN` is c The latest verified CI run for PR #17 is [40936739361](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40936739361), for commit `78f89b0` on `feat/doppler-integration`. All four jobs passed: -- `test`: compilation, migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, Docker build, non-root check, container smoke test, and Codecov upload. +- `test`: compilation, migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, Docker build, non-root check, container smoke test, and Codecov upload. The workflow also syntax-checks the example Nginx configuration with a temporary self-signed certificate; this does not verify a real certificate, public TLS, or live proxy routing. - `postgres-integration`: PostgreSQL migration, locking, and lease-fencing checks. - `dependency-audit`: resolved Python dependency audit. - `security`: CodeQL analysis and SARIF publication. From 653533024fbac2ba60c053680bb884a1b1a5d984 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:45:24 +0530 Subject: [PATCH 34/43] feat: support free-tier combined api and worker deployment --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 1c561ea..7a23a1c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,4 +7,4 @@ COPY src ./src RUN pip install --no-cache-dir . USER 10001:10001 EXPOSE 8000 -CMD ["sh", "-c", "alembic upgrade head && exec uvicorn fluxqueue.main:app --host 0.0.0.0 --port 8000"] +CMD ["sh", "-c", "alembic upgrade head && if [ \"${RUN_WORKER:-false}\" = \"true\" ]; then python -m fluxqueue.worker & fi; exec uvicorn fluxqueue.main:app --host 0.0.0.0 --port \"${PORT:-8000}\""] From 6e0bf52b59cd1de87d3223e90c1d32cf350d7fd6 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:47:24 +0530 Subject: [PATCH 35/43] docs: record free-tier demo deployment and CI status --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 65f7c54..b28bffd 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A durable job-processing platform built with FastAPI, SQLAlchemy, and PostgreSQL. -> **Current status (2026-10-30):** Docker-first local staging passed, and CI for PR #17 passed at [run 40936739361](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40936739361), head `78f89b0`. Test, PostgreSQL integration, dependency audit, and security jobs passed; Codecov upload is included in the test job. The PR remains open and unmerged. These results do not establish production readiness. +> **Current status (2026-10-30):** Docker-first local staging passed. Free-tier demo deployment is available at [fluxqueue-api.onrender.com](https://fluxqueue-api.onrender.com), backed by a dedicated Neon PostgreSQL project in Singapore. The API container can run the worker alongside the API via `RUN_WORKER=true`, suitable for a small demo. CI passed all four jobs for commit `6535330` in [run 40938441694](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40938441694). Free-tier services may sleep and have usage limits; this is not a production availability guarantee. The PR remains open and unmerged. ## Current capabilities @@ -171,7 +171,7 @@ Codecov upload activates when the repository Actions secret `CODECOV_TOKEN` is c ## CI status and latest verification -The latest verified CI run for PR #17 is [40936739361](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40936739361), for commit `78f89b0` on `feat/doppler-integration`. All four jobs passed: +The latest verified CI run for PR #17 is [40938441694](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40938441694), for commit `6535330` on `feat/doppler-integration`. All four jobs passed: - `test`: compilation, migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, Docker build, non-root check, container smoke test, and Codecov upload. The workflow also syntax-checks the example Nginx configuration with a temporary self-signed certificate; this does not verify a real certificate, public TLS, or live proxy routing. - `postgres-integration`: PostgreSQL migration, locking, and lease-fencing checks. @@ -193,7 +193,7 @@ The Docker-first local staging run and its detailed checks are recorded above an - Run controlled load and soak tests; record throughput, latency percentiles, worker concurrency, and database utilization. - Implement and test API-key rotation/revocation workflow; self-service key management is not implemented. -Track evidence in [deployment readiness](docs/deployment-readiness.md). No cloud staging environment has been provisioned, and PR #17 remains open and unmerged. +Track evidence in [deployment readiness](docs/deployment-readiness.md). A free-tier demo deployment is provisioned on Render with a dedicated Neon PostgreSQL project; it is not production staging. Free-tier sleep/usage limits, a combined API/worker process, and the remaining deployment-owner gates above still apply. PR #17 remains open and unmerged. ## License From a8e80a182fa34432e40d4015ef47a8aefb1bdcac Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:48:08 +0530 Subject: [PATCH 36/43] fix: expose health endpoints for free-tier worker service --- src/fluxqueue/worker.py | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/fluxqueue/worker.py b/src/fluxqueue/worker.py index f2c6228..eb013be 100644 --- a/src/fluxqueue/worker.py +++ b/src/fluxqueue/worker.py @@ -6,12 +6,13 @@ import random import socket import time +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from datetime import UTC, datetime, timedelta from threading import Event, Thread from typing import Any from uuid import uuid4 -from sqlalchemy import or_, select, update +from sqlalchemy import or_, select, text, update from sqlalchemy.orm import Session from fluxqueue.db import SessionLocal @@ -309,10 +310,48 @@ def run_once(*, worker_id: str, lease_seconds: int = DEFAULT_LEASE_SECONDS) -> b return True +class _HealthHandler(BaseHTTPRequestHandler): + """Minimal health endpoints so a worker can run on a web-service free tier.""" + + def do_GET(self) -> None: + if self.path == "/health/live": + self.send_response(200) + self.end_headers() + self.wfile.write(b'{"status":"alive"}') + return + if self.path == "/health/ready": + try: + with SessionLocal() as session: + session.execute(text("SELECT 1")) + except Exception: + self.send_response(503) + self.end_headers() + self.wfile.write(b'{"status":"not_ready"}') + return + self.send_response(200) + self.end_headers() + self.wfile.write(b'{"status":"ready","database":"reachable"}') + return + self.send_error(404) + + def log_message(self, _format: str, *_args: object) -> None: + return + + +def _start_health_server() -> None: + """Bind the Render-assigned port when the worker is deployed as a web service.""" + port = os.environ.get("PORT") + if not port: + return + server = ThreadingHTTPServer(("0.0.0.0", int(port)), _HealthHandler) + Thread(target=server.serve_forever, name="worker-health-server", daemon=True).start() + + def main() -> None: """Poll until interrupted; each worker has a unique lease identity.""" import signal + _start_health_server() worker_id = f"{socket.gethostname()}:{os.getpid()}:{uuid4().hex[:8]}" poll_seconds = 1.0 shutdown = Event() From d2e372f8bac12383b89d3c9a0963d3d03825538b Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:48:28 +0530 Subject: [PATCH 37/43] style: sort worker health server imports --- src/fluxqueue/worker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fluxqueue/worker.py b/src/fluxqueue/worker.py index eb013be..994d9da 100644 --- a/src/fluxqueue/worker.py +++ b/src/fluxqueue/worker.py @@ -6,8 +6,8 @@ import random import socket import time -from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from datetime import UTC, datetime, timedelta +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from threading import Event, Thread from typing import Any from uuid import uuid4 From 4b9dec8521f03eb1192d90461fe15f326aec49f5 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:49:36 +0530 Subject: [PATCH 38/43] fix: opt in to worker health listener explicitly --- src/fluxqueue/worker.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fluxqueue/worker.py b/src/fluxqueue/worker.py index 994d9da..a15b80e 100644 --- a/src/fluxqueue/worker.py +++ b/src/fluxqueue/worker.py @@ -340,6 +340,8 @@ def log_message(self, _format: str, *_args: object) -> None: def _start_health_server() -> None: """Bind the Render-assigned port when the worker is deployed as a web service.""" + if os.environ.get("WORKER_HEALTH_SERVER", "").lower() != "true": + return port = os.environ.get("PORT") if not port: return From aad51466e174847674bcd3cfcc861d56d4621730 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 00:52:44 +0530 Subject: [PATCH 39/43] docs: record final green CI verification --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b28bffd..827eae0 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A durable job-processing platform built with FastAPI, SQLAlchemy, and PostgreSQL. -> **Current status (2026-10-30):** Docker-first local staging passed. Free-tier demo deployment is available at [fluxqueue-api.onrender.com](https://fluxqueue-api.onrender.com), backed by a dedicated Neon PostgreSQL project in Singapore. The API container can run the worker alongside the API via `RUN_WORKER=true`, suitable for a small demo. CI passed all four jobs for commit `6535330` in [run 40938441694](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40938441694). Free-tier services may sleep and have usage limits; this is not a production availability guarantee. The PR remains open and unmerged. +> **Current status (2026-10-30):** Docker-first local staging passed. Free-tier demo deployment is available at [fluxqueue-api.onrender.com](https://fluxqueue-api.onrender.com), backed by a dedicated Neon PostgreSQL project in Singapore. The API container can run the worker alongside the API via `RUN_WORKER=true`, suitable for a small demo. CI passed all four jobs for latest code commit `4b9dec8` in [run 40939078055](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40939078055). Free-tier services may sleep and have usage limits; this is not a production availability guarantee. The PR remains open and unmerged. ## Current capabilities From 41317c10065a9336bf07cc54ecbb9d9f1f827d79 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 01:07:31 +0530 Subject: [PATCH 40/43] ci: add scheduled end-to-end deployment smoke test --- .github/workflows/deployment-smoke.yml | 71 ++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 .github/workflows/deployment-smoke.yml diff --git a/.github/workflows/deployment-smoke.yml b/.github/workflows/deployment-smoke.yml new file mode 100644 index 0000000..4dd3d07 --- /dev/null +++ b/.github/workflows/deployment-smoke.yml @@ -0,0 +1,71 @@ +name: Deployment smoke test + +on: + workflow_dispatch: + schedule: + - cron: "17 4 * * 1" + +permissions: + contents: read + +concurrency: + group: fluxqueue-deployment-smoke + cancel-in-progress: false + +jobs: + smoke: + runs-on: ubuntu-latest + timeout-minutes: 8 + env: + BASE_URL: https://fluxqueue-api.onrender.com + API_KEY: ${{ secrets.FLUXQUEUE_API_KEY }} + steps: + - name: Validate required secret + shell: bash + run: | + if [[ -z "$API_KEY" ]]; then + echo "::error::Add repository Actions secret FLUXQUEUE_API_KEY using the active FluxQueue tenant API key." + exit 1 + fi + + - name: Check API liveness and database readiness + shell: bash + run: | + set -euo pipefail + curl --fail --silent --show-error --retry 3 --retry-delay 5 "$BASE_URL/health/live" + echo + curl --fail --silent --show-error --retry 3 --retry-delay 5 "$BASE_URL/health/ready" + echo + + - name: Submit and verify a real job lifecycle + shell: bash + run: | + set -euo pipefail + payload="$(jq -nc --arg marker "deployment-smoke-$(date +%s)" '{task_type:"echo",payload:{message:$marker},queue:"deployment-smoke",priority:5,max_attempts:2}')" + response="$(curl --fail --silent --show-error -X POST "$BASE_URL/api/v1/jobs" \ + -H "Authorization: Bearer $API_KEY" \ + -H 'Content-Type: application/json' \ + -H "Idempotency-Key: deployment-smoke-$(date +%s)" \ + --data "$payload")" + job_id="$(jq -er '.id' <<<"$response")" + echo "Submitted job id: $job_id" + for attempt in $(seq 1 30); do + current="$(curl --fail --silent --show-error "$BASE_URL/api/v1/jobs/$job_id" \ + -H "Authorization: Bearer $API_KEY")" + status="$(jq -r '.status' <<<"$current")" + echo "Poll $attempt: status=$status" + if [[ "$status" == "succeeded" ]]; then + jq -e '.result_json.payload.message | startswith("deployment-smoke-")' <<<"$current" >/dev/null + echo "End-to-end job processing passed." + exit 0 + fi + if [[ "$status" == "dead" || "$status" == "cancelled" ]]; then + echo "::error::Smoke job reached terminal status $status" + jq '{id,status,last_error}' <<<"$current" + exit 1 + fi + sleep 2 + done + echo "::error::Job did not succeed within 60 seconds." + jq '{id,status,last_error}' <<<"$current" + exit 1 From ce0ca12a04d61ee41e862d60eefed406cde0fc51 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 01:07:46 +0530 Subject: [PATCH 41/43] ci: make deployment smoke test explicitly opt-in --- .github/workflows/deployment-smoke.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deployment-smoke.yml b/.github/workflows/deployment-smoke.yml index 4dd3d07..a886365 100644 --- a/.github/workflows/deployment-smoke.yml +++ b/.github/workflows/deployment-smoke.yml @@ -2,8 +2,6 @@ name: Deployment smoke test on: workflow_dispatch: - schedule: - - cron: "17 4 * * 1" permissions: contents: read @@ -41,11 +39,12 @@ jobs: shell: bash run: | set -euo pipefail - payload="$(jq -nc --arg marker "deployment-smoke-$(date +%s)" '{task_type:"echo",payload:{message:$marker},queue:"deployment-smoke",priority:5,max_attempts:2}')" + marker="deployment-smoke-$(date +%s)" + payload="$(jq -nc --arg marker "$marker" '{task_type:"echo",payload:{message:$marker},queue:"deployment-smoke",priority:5,max_attempts:2}')" response="$(curl --fail --silent --show-error -X POST "$BASE_URL/api/v1/jobs" \ -H "Authorization: Bearer $API_KEY" \ -H 'Content-Type: application/json' \ - -H "Idempotency-Key: deployment-smoke-$(date +%s)" \ + -H "Idempotency-Key: $marker" \ --data "$payload")" job_id="$(jq -er '.id' <<<"$response")" echo "Submitted job id: $job_id" @@ -55,7 +54,7 @@ jobs: status="$(jq -r '.status' <<<"$current")" echo "Poll $attempt: status=$status" if [[ "$status" == "succeeded" ]]; then - jq -e '.result_json.payload.message | startswith("deployment-smoke-")' <<<"$current" >/dev/null + jq -e --arg marker "$marker" '.result_json.payload.message == $marker' <<<"$current" >/dev/null echo "End-to-end job processing passed." exit 0 fi From 5c8c4b475ee626b5892794744ffab8e1466c2653 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 01:20:31 +0530 Subject: [PATCH 42/43] docs: reconcile deployment closeout status --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 827eae0..d445e64 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A durable job-processing platform built with FastAPI, SQLAlchemy, and PostgreSQL. -> **Current status (2026-10-30):** Docker-first local staging passed. Free-tier demo deployment is available at [fluxqueue-api.onrender.com](https://fluxqueue-api.onrender.com), backed by a dedicated Neon PostgreSQL project in Singapore. The API container can run the worker alongside the API via `RUN_WORKER=true`, suitable for a small demo. CI passed all four jobs for latest code commit `4b9dec8` in [run 40939078055](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40939078055). Free-tier services may sleep and have usage limits; this is not a production availability guarantee. The PR remains open and unmerged. +> **Current status (2026-10-30):** The free-tier demo deployment is live at [fluxqueue-api.onrender.com](https://fluxqueue-api.onrender.com), backed by a dedicated Neon PostgreSQL project in Singapore. CI checks and the manual deployment smoke test have been reported green; the smoke workflow exercises API liveness/readiness and an authenticated echo job through worker completion. The API container can also run the worker alongside the API via `RUN_WORKER=true`. Free-tier services may sleep and have usage limits; this is a demo deployment, not a production availability guarantee. PR #17 remains open and unmerged. ## Current capabilities @@ -171,7 +171,7 @@ Codecov upload activates when the repository Actions secret `CODECOV_TOKEN` is c ## CI status and latest verification -The latest verified CI run for PR #17 is [40938441694](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40938441694), for commit `6535330` on `feat/doppler-integration`. All four jobs passed: +The latest recorded CI run for PR #17 is [40938441694](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40938441694), for commit `6535330` on `feat/doppler-integration`; all four jobs passed. The PR branch also includes a manually triggered deployment smoke workflow at [deployment-smoke.yml](.github/workflows/deployment-smoke.yml). The repository owner reports its checks are green: - `test`: compilation, migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, Docker build, non-root check, container smoke test, and Codecov upload. The workflow also syntax-checks the example Nginx configuration with a temporary self-signed certificate; this does not verify a real certificate, public TLS, or live proxy routing. - `postgres-integration`: PostgreSQL migration, locking, and lease-fencing checks. @@ -186,14 +186,14 @@ The Docker-first local staging run and its detailed checks are recorded above an - Confirm Codecov credential rotation/revocation in provider settings; the replacement upload succeeded in CI, but secret values cannot be read back through GitHub. - Validate Nginx syntax, certificates, TLS negotiation, and proxy behavior in an authorized disposable environment. The example is a starting point; `limit_req_zone` belongs in the Nginx `http {}` context. -- Verify managed PostgreSQL TLS, network restrictions, least-privilege credentials, backup restoration, and migration rollback against production-like data. +- Verify managed PostgreSQL network restrictions and least-privilege credentials; test backup restoration and migration rollback against production-like data. Neon automatic snapshot scheduling is not enabled for this project, so a manual snapshot exists but automated backup scheduling is not configured. - Exercise database outages, worker termination during handlers, lease expiry, retry exhaustion, and restart recovery. - Verify idempotency for every external side-effecting handler. - Configure and verify operational metrics, structured logs, alerts, on-call ownership, resource limits, log retention, and rollback procedures. - Run controlled load and soak tests; record throughput, latency percentiles, worker concurrency, and database utilization. - Implement and test API-key rotation/revocation workflow; self-service key management is not implemented. -Track evidence in [deployment readiness](docs/deployment-readiness.md). A free-tier demo deployment is provisioned on Render with a dedicated Neon PostgreSQL project; it is not production staging. Free-tier sleep/usage limits, a combined API/worker process, and the remaining deployment-owner gates above still apply. PR #17 remains open and unmerged. +Track evidence in [deployment readiness](docs/deployment-readiness.md). A free-tier demo deployment is provisioned on Render with a dedicated Neon PostgreSQL project; the smoke test is reported green, but the deployment is not production staging. Free-tier sleep/usage limits and the remaining deployment-owner gates above still apply. PR #17 remains open and unmerged. ## License From e28b7e6cd2c74ff6edfe369caa73bf86ab949245 Mon Sep 17 00:00:00 2001 From: Vankudothu Adhi Naik <22je1052@iitism.ac.in> Date: Fri, 30 Oct 2026 01:24:33 +0530 Subject: [PATCH 43/43] docs: record latest all-green CI run --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d445e64..31ee132 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,7 @@ Codecov upload activates when the repository Actions secret `CODECOV_TOKEN` is c ## CI status and latest verification -The latest recorded CI run for PR #17 is [40938441694](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40938441694), for commit `6535330` on `feat/doppler-integration`; all four jobs passed. The PR branch also includes a manually triggered deployment smoke workflow at [deployment-smoke.yml](.github/workflows/deployment-smoke.yml). The repository owner reports its checks are green: +The latest verified CI run for PR #17 is [40943705556](https://github.com/vankudothuadhinaik/FluxQueue/actions/runs/40943705556), for commit `5c8c4b4` on `feat/doppler-integration`; all four jobs passed. The PR branch also includes a manually triggered deployment smoke workflow at [deployment-smoke.yml](.github/workflows/deployment-smoke.yml). The repository owner reports its checks are green: - `test`: compilation, migration checks, Ruff, unit/API tests, Compose and Doppler wiring validation, Docker build, non-root check, container smoke test, and Codecov upload. The workflow also syntax-checks the example Nginx configuration with a temporary self-signed certificate; this does not verify a real certificate, public TLS, or live proxy routing. - `postgres-integration`: PostgreSQL migration, locking, and lease-fencing checks.