Retry unconfirmed proof publication instead of trusting future file dates
This commit is contained in:
@@ -131,7 +131,7 @@ The application deployment still follows the pinned updater below. Activate work
|
||||
|
||||
`revalidate.py` and `examples/otche-revalidation.{service,timer}` renew **both** owner ACL/storage/QGA isolation and online network proofs from new disposable resources. They do not requalify Windows revisions, change source VMs, edit old expiry dates, or deploy application images. Use reviewed clean backend/deploy checkouts on the host and pin their full commits in a root-owned mode0600 `/etc/otche-revalidation.json`, based on `examples/revalidation.example.json`. Adapt the existing control CT, Compose project/container/network names, worker-config mount, owner and stopped source reference; example identities are not live inventory. The five owner credentials and network client certificate are read from the existing private control-CT mount and staged only in a private run directory. No credentials belong in the scheduler config or Git.
|
||||
|
||||
The persistent timer checks every fifteen minutes. Work starts only when either proof has eight hours or less remaining. Successful actual probes issue at most 24 hours of validity; busy deployments defer to the next tick rather than interrupt a job. PostgreSQL SHARE locks cover the idle observation and freezing the exact worker container: unfinished attempts, queued/running qualifications, retained allocations/extractors/media all prevent testing. The API stays available; submissions during the check wait in the queue. The idle worker heartbeat is temporarily stale. `ExecStopPost` thaws only the exact recorded container, including after a timeout. Do not run updates, source maintenance, restores or another operator probe concurrently.
|
||||
The persistent timer checks every fifteen minutes. The first run and an unconfirmed proof publication require a full cycle; thereafter work starts when either proof has eight hours or less remaining. Successful actual probes issue at most 24 hours of validity; busy deployments defer to the next tick rather than interrupt a job. PostgreSQL SHARE locks cover the idle observation and freezing the exact worker container: unfinished attempts, queued/running qualifications, retained allocations/extractors/media all prevent testing. The API stays available; submissions during the check wait in the queue. The idle worker heartbeat is temporarily stale. `ExecStopPost` thaws only the exact recorded container, including after a timeout. Do not run updates, source maintenance, restores or another operator probe concurrently.
|
||||
|
||||
The cycle full-clones the stopped source, verifies its configuration is unchanged, runs fresh owner allow/deny probes, exercises isolated real kernel packet tests plus live Windows networking through the actual broker, and verifies expiry/restart revocation. A temporary DHCP macvlan target supplies the LAN positive control; it never adds host-root addresses or forwards traffic. Configure reachable public TCP/DNS positive controls and explicit protected PVE/panel/router targets. Any missing positive control fails the check rather than inventing a denial result. Only after verified cleanup are both evidence hashes validated, new proof files atomically replaced and `bindings-sync` run in the existing approved worker image. Application repositories/images, accounts, data volumes, source seals and qualifications are untouched.
|
||||
|
||||
|
||||
+10
-1
@@ -82,10 +82,19 @@ class Renewal:
|
||||
config = json.loads(self.ct('cat', self.c['worker_config']))
|
||||
self.binding = config['owners'][self.c['owner_id']]
|
||||
self.runtime_config = config
|
||||
for key in (self.binding['isolation_proof_file'], self.binding['online']['proof_file']):
|
||||
success_path = self.state / 'last-success.json'
|
||||
if not success_path.exists():
|
||||
return True
|
||||
success = load(success_path)
|
||||
for key, field in ((self.binding['isolation_proof_file'], 'isolation_expires_at'),
|
||||
(self.binding['online']['proof_file'], 'online_expires_at')):
|
||||
try:
|
||||
proof = json.loads(self.ct('cat', self.host_path(key)))
|
||||
expiry = dt.datetime.fromisoformat(proof['expires_at'].replace('Z', '+00:00'))
|
||||
published = dt.datetime.fromisoformat(success[field].replace('Z', '+00:00'))
|
||||
if (proof.get('passed') is not True or proof.get('owner_id') != self.c['owner_id']
|
||||
or proof.get('node') != self.binding['node'] or abs((expiry - published).total_seconds()) >= .001):
|
||||
return True
|
||||
if expiry <= dt.datetime.now(dt.timezone.utc) + dt.timedelta(hours=8):
|
||||
return True
|
||||
except (RuntimeError, ValueError, KeyError):
|
||||
|
||||
Reference in New Issue
Block a user