P7 r3 fix: single-preview contract (syncAccess delegates drift-check+preview+push to pushIfNoDrift; acl_preview_failed mapped non-retryable) + test updates

This commit is contained in:
Hermes committed 2026-10-03 22:55:22 -07:00
1 parent d2d0d73477
commit 1e606bf0f3
2 files changed
+18 -22

No files matched your search

@@ -334,8 +334,9 @@ function createTailscaleProvider({
* DC-148 via src/network/acl-sync.js). Safety sequence, spec §4:
* 1. compileAndValidate — LockoutError → ProviderError 'lockout_guard'
* (retryable:false), nothing compiled-past let alone pushed
* 2. previewPolicy — ANY preview error → ProviderError
* 'acl_preview_failed', NOTHING pushed
* 2. drift guard + preview + push via pushIfNoDrift — ANY preview error
* → ProviderError 'acl_preview_failed', NOTHING pushed; a drifted
* remote → 'acl_drift_detected'; the policy is previewed EXACTLY once
* 3. pushPolicy — API failure maps through the usual coord vocabulary;
* success → { pushed: true, hash, usersAffected }
*
@@ -400,19 +401,9 @@ function createTailscaleProvider({
throw toProviderError(err);
}
try {
// ANY preview error refuses the push (AclPushError from acl-push).
await engine.preview(compiled.policy);
} catch (err) {
if (err instanceof AclPushError) {
throw new ProviderError(
'tailscale: ACL preview failed — refusing to push (' + err.message + ')',
{ code: 'acl_preview_failed', retryable: false, cause: err }
);
}
throw toProviderError(err);
}
// Push goes through the drift guard: pushIfNoDrift performs
// drift-check → preview → push in ONE pass, so the policy is previewed
// EXACTLY once (a preview error throws before anything is pushed).
let pushed;
try {
pushed = await engine.push(compiled.policy);
@@ -434,11 +425,13 @@ function createTailscaleProvider({
let code = 'server_error';
if (err.code === 'acl_rejected') code = 'bad_input';
else if (err.code === 'rate_limited') code = 'rate_limited';
else if (err.code === 'acl_preview_failed') code = 'acl_preview_failed';
const opts = { code, cause: err };
opts.retryable =
err.code === 'rate_limited' ||
String(err.code).startsWith('http_429') ||
code === 'server_error';
if (code === 'acl_preview_failed') opts.retryable = false;
throw new ProviderError('tailscale: ACL push failed — ' + err.message, opts);
}
throw toProviderError(err);