Repository navigation
device_monitoring: publish to ingest API; token from Secret Manager; hardened MSI cron - #134
Merged
runck014 merged 7 commits intoOct 16, 2026
Conversation
A fresh install resolves SQLAlchemy 2.1, whose default PostgreSQL driver is psycopg (v3), which is not a dependency; every GEMS query then fails with "No module named 'psycopg'" (seen 2026-10-14 in a clean venv of 7098865). uv.lock already holds 2.0.41, but install.sh runs `uv pip install -e .[all]`, which does not read the lock, so a rebuilt MSI venv would break the same way. Co-Authored-By: Claude Opus 5.5 <[email protected]>
GEMS is reachable only inside UMN, so the cron on MSI stays the puller. With DEVICEMON_INGEST_URL and DEVICEMON_INGEST_TOKEN set, monitor() now saves the run as a devmon-batch/1 JSON file and POSTs it to rtgs- infrastructure's device-monitoring-ingest (retries with backoff on network errors, 429 and 5xx) instead of writing Cloud SQL with a service-account key. Without them the old direct write still runs. produce_db gains monitoring_records / logger_info_records / app_config_defaults so both paths store identical values. New command: rtgs device-monitoring publish FILE re-sends a saved batch (idempotent). Co-Authored-By: Claude Opus 5.5 <[email protected]>
… versioned scrontab The script passed --start_date/--end_date/--node_ids; the CLI defines --start-date/--end-date/--node-ids, so any dated run failed with "No such option". The cron now runs a release tag instead of git pull on whatever branch the clone is on: DEVICEMON_RELEASE=devmon-vX.Y.Z pins it (a one-line edit on MSI deploys), track:devmon-v* follows the newest tag (a tag push deploys). If the release carries a newer copy of this script it re-runs that copy once. Credentials (main file plus ~/.rtgs_creds.d/*.env drop- ins) load before the checkout; the run refuses to start with no publish target instead of writing SQLite inside the clone. The scrontab line lives in scrontab.msi. Co-Authored-By: Claude Opus 5.5 <[email protected]>
bash -n on the cron script, publisher tests (schema, batch id, retry policy, flag names), and the CLI flags the cron passes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Defaults to /projects/standard/runck014/shared/device_monitoring (Bryan's scrontab): DEVICEMON_BASE_DIR, DEVICEMON_WORK_DIR, DEVICEMON_LOG_DIR, DEVICEMON_CREDS_FILE (credentials/.rtgs_credentials, 660 group runck014), DEVICEMON_BATCH_DIR (logs/batches). umask 007. Per-user ~/.rtgs_credentials and ~/.rtgs_creds remain fallbacks; ~/.rtgs_creds.d is dropped. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_0149VSJ7dmCkXd4UcUjQbG9R
The publisher reads devicemon-ingest-token (prod URL) or devicemon-ingest-token-test (test URL) from Secret Manager at run time with a service-account key (DEVICEMON_SA_KEY, default ~/.config/devmon/sa.json) and holds it in memory only, so rotating the token never touches MSI. The key must be a regular file owned by the running user, mode 600; anything else fails closed. The token is sent only to the known ingest hosts, and the secret must match the host. DEVICEMON_INGEST_TOKEN stays as an explicit test override. - new `rtgs device-monitoring check-ingest`: fetch the token, call /health and /v1/status, print the secret version and HTTP statuses (exit 2 setup, 3 transient) - save_batch creates files with O_EXCL|O_NOFOLLOW (the batch dir is group-writable)
…logs
- the shared credentials file is parsed (KEY=VALUE, allowlist), never sourced; *_DIR, *_FILE,
PATH, LD_*, PYTHON*, GOOGLE_*, DEVICEMON_RELEASE and the token are refused from it
- release pin from ~/.config/devmon/release ("<tag> <sha>"), both checked; git runs with
core.hooksPath=/dev/null; no fetch --tags --force; track: mode removed
- refuses to run if this script, its dir, the checkout or the venv is group/world-writable
or not owned by the running user; umask 027
- log file created by mktemp and held open on fd 3; lock in ~/.cache/devmon
- check-ingest preflight before the pipeline; DEVICEMON_INGEST_TOKEN unset in the cron
- --check-creds <file> lists accepted/rejected names (value lengths only)
- CI runs all device_monitoring tests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
devmon MSI publisher: ingest key from Secret Manager (FRI 2026-10-16)
MSI never holds the ingest token. Each run the publisher reads it from Secret Manager with a
service-account key that can read the two token secrets and nothing else. Nothing below has been
run against GCP or MSI; the patch is not pushed.
Flow
What MSI holds
~/.config/devmon/sa.json: SA key, 600, Bryan's home. Can read the 2 token secrets, nothingelse (secret-level bindings; no project roles).
~/.config/devmon/release:devmon-vX.Y.Z <40-hex sha>, 600. Editing this line deploys.credentials/.rtgs_credentials(660): URL + GEMS/Particle/Gmail. No token. ADEVICEMON_INGEST_TOKENline is ignored and logged as "delete it".Order (Bryan)
03-output-20261016-devmon-rtgs-lab-tools.patch(7 commits on 7098865); pushthe branch, PR, merge, tag
devmon-v0.1.0; note the tag's commit SHA.bash 06-output-20261016-devmon-msi-sa-setup.sh(dry run), thenDRY_RUN=0 bash 06-output-20261016-devmon-msi-sa-setup.sh(y/N per change).(umask 077; printf 'devmon-v0.1.0 <sha>\n' > ~/.config/devmon/release)scripts/andrtgs-lab-tools-cron/aside, re-create them as yours 2750;chmod 2770 logs logs/batches.The script refuses to run until the code side is yours and not group-writable.
DEVICEMON_INGEST_URLto the TEST host in the credentials file, delete any tokenline, check:
scripts/scheduled_device_monitoring.sh --check-creds credentials/.rtgs_credentialsscrontab.Test sequence (agate shell, venv active, against test)
The empty batch writes one row to
ingest_batchesin device_monitoring_test (shows in/v1/status);
full_fleet=Falseso no logger is marked inactive. Token never on a command line.Rotate the API key
Services pin token versions by number (checked 14:35: test ->
devicemon-ingest-token-test:1,prod ->
devicemon-ingest-token:1; 05-context). MSI readslatest. So a version must neverbe added without a redeploy, or MSI gets 401 until the service is redeployed.
devmon-rotate-ingest-token.yml(rtgs-infrastructure):phase=addadds aversion AND redeploys accepting new + previous. MSI picks up the new one next run; nothing to
do on MSI. After one green run:
phase=retire.Rotate the SA key
gcloud iam service-accounts keys list --iam-account=... --managed-by=usershows the IDs.Open
--check-credslists what it accepts.LOGGING_INSTANCE_CONNECTION_NAMEand the direct Cloud SQL path are not accepted (removed).~/.config/devmon/msi.envstill holds the prod token from dir 02; not needed on MSI.🤖 Generated with Claude Code
https://claude.ai/code/session_0149VSJ7dmCkXd4UcUjQbG9R