# Local agent action gateway health checks

Local action gateway तभी स्वस्थ माना जा सकता है जब वह गलत कार्रवाई को रोक सके, सही नियंत्रित कार्रवाई कर सके और ऐसा प्रमाण छोड़े जो review के दौरान भी बना रहे। Green process monitor इससे लगभग कुछ भी साबित नहीं करता। वह केवल बताता है कि कोई process मौजूद है। वह यह नहीं बताता कि वॉल्ट locked है या नहीं, agent gateway तक पहुंच सकता है या नहीं, injected credentials अभी काम कर रहे हैं या नहीं, या audit trail ने call दर्ज की या नहीं।

Sallyport के मामले में यह अंतर महत्वपूर्ण है, क्योंकि app, vault gate, authorization decision, external action और encrypted audit log failure के अलग-अलग बिंदु हैं। इन्हें एक सामान्य «health» signal मानने से monitoring का सबसे खराब रूप बनता है: ऐसा monitor जो green रहता है, जबकि वह control काम करना बंद कर चुका होता है जिस पर आप निर्भर हैं।

इसे port checks के ढेर की तरह नहीं, बल्कि एक छोटी acceptance suite की तरह बनाएं। Suite को harmless canary targets इस्तेमाल करने चाहिए, non-secret evidence लौटाना चाहिए और locked vault को सही तरह classify करना चाहिए। अगर किसी व्यक्ति को Touch ID से वॉल्ट unlock करना पड़ता है, तो monitor को यह स्थिति साफ़-साफ़ report करनी चाहिए, उसे bypass करने की कोशिश नहीं करनी चाहिए।

## Running app केवल पहली शर्त है

Availability probe का जवाब एक सीमित सवाल पर होना चाहिए: क्या local Mac gateway app को शुरू करके चलाए रख सकता है? इसे यह मानने का दिखावा नहीं करना चाहिए कि running process से external actions भी साबित हो जाती हैं।

Menu-bar app के लिए शुरुआत ऐसे local check से करें जिसे supervisor credentials के बिना चला सके। Process name और install location release के हिसाब से बदल सकते हैं, इसलिए इन values को scripts में जगह-जगह लिखने के बजाय एक local configuration file में रखें। Basic shell probe ऐसा हो सकता है:

```sh
#!/bin/sh
set -eu

APP_NAME="Sallyport"

if ! pgrep -x "$APP_NAME" >/dev/null 2>&1; then
  open -a "$APP_NAME"
  sleep 2
fi

if pgrep -x "$APP_NAME" >/dev/null 2>&1; then
  printf 'app=ready\n'
  exit 0
fi

printf 'app=unavailable\n' >&2
exit 2
```

इसका दावा जानबूझकर सीमित है। `open -a` macOS से application launch करने को कहता है और `pgrep` उस request के बाद process को देखता है। इससे यह साबित नहीं होता कि app ने initialization पूरा कर लिया है, उसका vault किसी request का जवाब दे सकता है या उसका MCP shim client स्वीकार कर सकता है। Apple Launch Services को applications launch और activate करने के लिए इस्तेमाल होने वाले system interface के रूप में document करता है। इसलिए application bundle path को hard-code करने के बजाय operating system के जरिए launch करना बेहतर है।

Output को structured और साधारण रखें। Scheduler के लिए `app=ready` काफी है। `ps` output को central log में न डालें, जहां command arguments, usernames या असंबंधित process details हमेशा के लिए जमा हो जाएं।

Process मौजूद हो सकता है, फिर भी अटक गया हो। Mac के sleep में होने, user के logged out होने या update के बाद restart होने के कारण process अनुपस्थित भी हो सकता है। Alerting rule में इन अपेक्षित स्थितियों के लिए grace period रखें। हर बार laptop का lid बंद होने पर page करने वाला health check बंद कर दिया जाएगा और फिर असली failure के समय मदद नहीं करेगा।

इसलिए उपयोगी availability signal local और सीमित होता है: app शुरू हुआ, थोड़ी settling अवधि तक मौजूद रहा और MCP client session शुरू कर सकता है। आखिरी हिस्सा अलग probe में होना चाहिए, क्योंकि वह दूसरी सीमा को exercise करता है।

## Vault state को स्पष्ट result होना चाहिए

Locked vault तब healthy होता है जब वह actions को deny करता है। इस स्थिति को outage कहना security behavior को service failure के साथ मिला देता है।

Sallyport का vault gate पूर्ण है: locked रहते हर action deny होती है। Supported macOS hardware पर vault gate Secure Enclave और Touch ID का इस्तेमाल करता है। Check को इस नियम को बनाए रखना चाहिए। ऐसा script न लिखें जो UI में passwords डालता हो, biometric bypass token रखता हो या unlocked desktop session को इस बात का प्रमाण मानता हो कि vault unlock होना चाहिए।

Boolean के बजाय चार result states इस्तेमाल करें:

- `ready`: app उपलब्ध है, vault unlocked है और controlled checks चल सकती हैं।
- `locked`: app उपलब्ध है, लेकिन vault actions को सही ढंग से deny कर रहा है।
- `denied-unexpectedly`: vault unlocked है, फिर भी intended canary action deny हो गई।
- `unavailable`: app या उसका local MCP path जवाब नहीं दे सकता।

यह vocabulary एक आम operational गलती रोकती है। Teams अक्सर रात में credentialed probe schedule करती हैं, screen lock होने के बाद failures देखती हैं और system को तब तक कमजोर करती हैं जब तक वह खुद unlock न होने लगे। उन्होंने monitoring ठीक नहीं की। उन्होंने वह human decision हटा दिया जिसकी मांग vault को करनी थी।

व्यावहारिक तरीका दो हिस्सों वाला run है। Unattended job app availability और locked-vault denial record करे। कोई व्यक्ति, या ऐसा controlled workstation session जिसे पहले से human approval मिला हो, unlock करने के बाद credentialed checks शुरू करे। Run output में कारण दर्ज करें:

```json
{
  "run_id": "hc-2026-07-22T141501Z-8f29",
  "app": "ready",
  "vault": "locked",
  "http": "skipped",
  "ssh": "skipped",
  "audit": "verified",
  "reason": "credentialed checks require an unlocked vault"
}
```

Run ID secret नहीं है। इससे operators बाद में activity record से तुलना करने के लिए स्थिर reference पा लेते हैं। Run ID के रूप में username, machine serial number, endpoint URL या credential label का इस्तेमाल न करें।

Per-session authorization और per-call approval को भी अलग तरह से संभालना होगा। नए agent process के लिए session approval जरूरी हो सकती है और किसी credential के हर इस्तेमाल पर approval जरूरी हो सकती है। यह अपेक्षित behavior है, flaky test नहीं। Runner को बताना चाहिए कि वह approved session के लिए बना है या हर call को कोई व्यक्ति approve करेगा। चुपचाप होने वाला timeout अगले investigator को कुछ नहीं बताता।

## Credential injection साबित करने वाले canary targets इस्तेमाल करें

HTTP check को ऐसे endpoint को call करना चाहिए जो किसी specific canary credential को validate करने के लिए बनाया गया हो और fixed, non-secret result लौटाए। Public URL test करने से केवल network काम करने की पुष्टि होती है। इससे यह पता नहीं चलता कि gateway ने सही credential चुना, उसे सही header में डाला या agent से दूर रखा।

एक छोटी service बनाएं जो एक path, एक method और एक credential form स्वीकार करे। Expected canary secret service side पर रखें। Gateway vault में वही canary secret रखें। Action शुरू करने वाला client secret कभी प्राप्त न करे और service उसे कभी echo न करे।

Response contract इतना छोटा हो सकता है:

```json
{
  "check": "agent-gateway-http",
  "result": "ok",
  "request_id": "7d7a0f3c"
}
```

Credential अनुपस्थित या गलत होने पर service को `401`, गलत method पर `405` और expected credential मिलने पर ही `200` लौटाना चाहिए। `request_id` service पर generate करें और उसे opaque रखें। इसे authorization header या incoming request के किसी हिस्से से न बनाएं।

Dedicated route जैसे `/agent-gateway-canary` का इस्तेमाल करें। Check को किसी मौजूदा production endpoint पर न जोड़ें। Production endpoints समय के साथ rate limits, redirects, content negotiation, caching rules, billing side effects और permission changes जमा कर लेते हैं। Canary route जानबूझकर साधारण रह सकता है।

RFC 9110 request method semantics को define करता है और GET, HEAD, OPTIONS तथा TRACE को safe methods में रखता है। लेकिन HTTP में safe का अर्थ है कि requested action resource की intended state नहीं बदलेगी। इसका अर्थ यह नहीं कि call आपके account, logs, quotas या downstream behavior के लिए harmless है। कोई API GET record कर सकता है, request का charge लगा सकता है या खराब implementation के कारण side effect शुरू कर सकता है। ऐसा route बनाएं जिसका server-side behavior आप inspect कर सकें, किसी परिचित verb पर भरोसा न करें।

एक आम खराब सलाह production API token के साथ `curl` को health check के रूप में इस्तेमाल करना है। यह लोकप्रिय है क्योंकि एक line में हो जाता है। यह गलत है, क्योंकि shell history, process inspection, CI logs और error output bearer token के दिखने की बहुत-सी जगहें बना देते हैं। अगर gateway सामान्यतः credentials खुद inject करता है, तो इससे वह behavior भी test नहीं होता जिसे आपको जांचना है।

Runner को gateway को उसी MCP route से call करना चाहिए जिसका agent इस्तेमाल करता है। Check के लिए कोई backdoor HTTP client न बनाएं। Transport-specific invocation को local adapter के पीछे रखें, क्योंकि tool names और request shapes बदल सकते हैं। Adapter logical action लेता है, MCP-connected gateway से उसे करने को कहता है और केवल normalized result निकालता है।

```json
{
  "action": "http_canary",
  "target": "canary-api",
  "method": "POST",
  "path": "/agent-gateway-canary",
  "expected_status": 200,
  "expected_check": "agent-gateway-http"
}
```

Failure होने पर adapter को redact करना चाहिए। वह `http_status=401`, `transport_error=timeout` या `response_schema=invalid` report कर सकता है। उसे outgoing headers, request body, query parameters वाला पूरा URL या raw response print नहीं करना चाहिए, जब तक आपने उस data को safe review न किया हो।

## HTTP success को intended action साबित करनी चाहिए

अपने आप में `200` कमजोर evidence है। Check को service response, method और target identity validate करनी चाहिए, ताकि redirect, proxy page या stale fixture false pass न बन जाए।

Canary response में credential की पहचान किए बिना test की पहचान होनी चाहिए। कुछ exact fields की तुलना करें:

```sh
status=200
check=agent-gateway-http
result=ok
request_id=7d7a0f3c
```

Checker को syntactically valid किसी भी `request_id` को स्वीकार करना चाहिए और उसे run ID के साथ save करना चाहिए। Missing field, success का दावा करने वाली लेकिन non-2xx status वाली body और unexpected content type को reject करें। Captive portal, corporate proxy error page या misrouted DNS record अक्सर valid HTTP response लौटाते हैं। यह transport success है, action success नहीं।

curl documentation इससे जुड़ी बात बताता है: `--fail` या `--fail-with-body` के बिना curl 404 या 401 जैसे HTTP status को command failure नहीं मानता। General transfer client के लिए यह behavior सही है, लेकिन जो लोग केवल curl के exit status को देखकर monitor लिखते हैं, वे फंस जाते हैं। अगर आपका adapter अंदर से curl इस्तेमाल करता है, तो process result और HTTP status दोनों capture करें और अपने explicit contract से success तय करें।

जब तक redirects intended endpoint design का हिस्सा न हों, check को उन्हें अपने आप follow न करने दें। Redirect canary call को login page पर भेज सकता है जो `200` लौटाती है, या ऐसे host पर भेज सकता है जहां आप जाना नहीं चाहते थे। Configuration में HTTPS origin को pin करें, normal client stack के जरिए certificate validate करें और final peer identity तभी record करें जब उससे sensitive network details उजागर न हों।

Timeouts को अलग labels दें। DNS failure, TCP refusal, TLS validation failure, gateway denial, upstream `401`, upstream `500` और response mismatch के owners अलग होते हैं। अगर runner इन सभी को `http=failed` कहेगा, तो हर incident के पहले दस मिनट यह पता लगाने में निकलेंगे कि request कहां रुकी।

Useful failure record ऐसा हो सकता है:

```json
{
  "run_id": "hc-2026-07-22T141501Z-8f29",
  "check": "http_canary",
  "outcome": "failed",
  "stage": "upstream_response",
  "http_status": 401,
  "request_id": null,
  "secret_material": "redacted"
}
```

`secret_material` line record पढ़ने वाले लोगों के लिए reminder है, redaction के काम करने का प्रमाण नहीं। Redaction को tests से साबित करें: Canary को जानबूझकर credential reject करने दें, runner के stdout और stderr capture करें और उन files में test secret खोजें। Secret नहीं मिलना चाहिए। यही जांच malformed JSON, timeout, TLS failure और agent-side tool error के साथ दोहराएं। Secrets अक्सर error paths से बाहर निकलते हैं।

## SSH को fenced target चाहिए, login shell नहीं

SSH health check को ऐसे dedicated account के खिलाफ authentication और command execution साबित करना चाहिए जिसका server arbitrary commands चलाने से इनकार करता हो। General administrative host से सफल connection गलत दिशा में बहुत कुछ साबित करता है: health credential को useful shell मिल जाता है।

Controlled test host पर `gateway-health` जैसा अलग account बनाएं। `authorized_keys` या equivalent server-side restriction में forced command दें। Forced command को original command न मानते हुए local audit file में timestamp और opaque run ID लिखना चाहिए, फिर constant response लौटाना चाहिए।

Conceptual `authorized_keys` entry ऐसी दिख सकती है:

```text
command="/usr/local/libexec/gateway-health",no-port-forwarding,no-agent-forwarding,no-X11-forwarding,no-pty ssh-ed25519 AAAA... gateway-health
```

Public key gateway की canary identity की होगी। Private key vault में रहेगी। यहां `AAAA...` text जानबूझकर अधूरा है, क्योंकि आपको अपनी key material generate करनी है, production file में example copy नहीं करना।

Server command को `$SSH_ORIGINAL_COMMAND`, environment variables या authentication details echo नहीं करने चाहिए। यह fixed shape लौटा सकता है:

```json
{"check":"agent-gateway-ssh","result":"ok","receipt":"c2b91a"}
```

Correlation के लिए run ID चाहिए तो submitted command में opaque token भेजें और forced command से hexadecimal characters के fixed length जैसे tight format को validate कराएं। Arbitrary string को कभी shell command, filename या log line में लिखने की अनुमति न दें। इससे भी बेहतर है कि server receipt generate करे और investigation के समय time window से records मिलाए।

अगर server interactive shell, port forwarding, TTY allocation या forced command के अलावा कोई command चलाने देता है, तो check fail होना चाहिए। ये configuration regressions हैं। Routine network timeout की तुलना में इनकी severity अलग होनी चाहिए, क्योंकि ये canary credential का exposure बदलते हैं।

Deployment के लिए इस्तेमाल होने वाली SSH identity को reuse न करें। Reuse से check setup करना आसान होता है, फिर monitoring failure व्यापक access problem बन जाता है। Health credential का एक ही काम, एक target account और receipt बनाने से अधिक कोई permission नहीं होनी चाहिए।

Sallyport SSH को अपने bundled stateless `sp-ssh` helper के जरिए भेजता है। इसलिए आपका test local private key के साथ OpenSSH चलाने के बजाय normal gateway action path से जाना चाहिए। वरना आपने केवल host और account जांचे हैं। आपने उस credential boundary को छोड़ दिया है जिसे साबित करना जरूरी है।

## Audit verification अलग assertion है

Successful canary action और valid audit trail दो अलग claims हैं। दोनों को verify करें।

Activity record बताता है कि gateway ने individual action record की। Session record agent run के बारे में बताता है और उस run को revoke करने का तरीका देता है। इनमें से किसी को remote effect की जांच का substitute न मानें, क्योंकि upstream failure से पहले request log हो सकती है। उलटे, local logging path सही समय पर fail होने के बावजूद remote system को request मिल सकती है। आपको wishful thinking नहीं, correlation चाहिए।

हर successful HTTP या SSH action के लिए तीन non-secret evidence pieces जुटाएं:

- runner द्वारा generate किया गया health run ID;
- canary service द्वारा generate की गई opaque receipt या request ID;
- UTC में record किया गया local action timestamp।

फिर activity journal में ऐसे action metadata देखें जिन्हें सुरक्षित रूप से रखा जा सकता है, जैसे channel, action outcome, target alias और time। Journal में plaintext credentials होने की उम्मीद न करें। ऐसा होना भी नहीं चाहिए। उससे remote response body दोबारा बनवाने की मांग न करें। Receipt remote canary system की है, gateway secret store की नहीं।

Sallyport अपने Sessions और Activity journals को write-blind, encrypted और hash-chained audit log से project करता है। Suite के स्वतंत्र हिस्से के रूप में इसका offline integrity check चलाएं:

```sh
sp audit verify
```

सफल command को `audit=verified` के रूप में record करें। Nonzero result को तब तक integrity incident मानें जब तक इसके विपरीत साबित न हो। इस verification को vault key की जरूरत नहीं होती, इसलिए vault locked होने पर भी यह unattended local check के लिए उपयुक्त है।

Audit verification को «log file मौजूद है» तक सीमित न करें। File existence लगभग कुछ नहीं पकड़ती। Truncated file, बदले हुए records, टूटी chain या startup के बाद रुक गया writer, सभी Finder में सामान्य दिखने वाले path के साथ मौजूद हो सकते हैं।

एक और आसान गलती केवल audit chain validate करना है। Chain valid हो सकती है, फिर भी expected event न हो, क्योंकि gateway ने action की कोशिश ही नहीं की। हर canary action के बाद chain verification को event-presence assertion के साथ जोड़ें। Local projection के लिए reasonable arrival window तय करें और delay को missing event से अलग report करें। Delayed journal update की जांच जरूरी हो सकती है, लेकिन वह failed write के बराबर नहीं है।

## Runner को उस trust boundary से बाहर रखें जिसे वह जांचता है

Health runner को actions orchestrate करने और evidence का फैसला करने का काम करना चाहिए। उसके पास credentials नहीं होने चाहिए, उसे vault files parse नहीं करनी चाहिए और secret-bearing application state पढ़नी नहीं चाहिए।

Practical layout में चार components होते हैं:

1. Local scheduler dedicated macOS account के तहत छोटा runner launch करता है।
2. Runner app presence check करता है और local MCP adapter को call करता है।
3. Adapter gateway के जरिए named canary actions मांगता है और redacted structured results लौटाता है।
4. Runner audit integrity verify करता है और protected local directory में एक छोटी report लिखता है।

Dedicated account को vault की data files तक access नहीं होना चाहिए। Apple non-sandboxed macOS application support data को current user's `~/Library/Application Support` directory में रखता है, लेकिन monitor को यह assume नहीं करना चाहिए कि वह उन files को inspect कर सकता है या करना चाहिए। Check को vault contents की copy नहीं, behavior चाहिए।

Configuration को declarative और secrets से मुक्त रखें। यह example runner को credentials बताए बिना outcomes validate करने के लिए पर्याप्त information देता है:

```yaml
checks:
  http_canary:
    target_alias: canary-api
    expected_status: 200
    expected_check: agent-gateway-http
    timeout_seconds: 10
  ssh_canary:
    target_alias: canary-ssh
    expected_check: agent-gateway-ssh
    timeout_seconds: 10
  audit:
    command: sp audit verify
    timeout_seconds: 15
```

Target aliases महत्वपूर्ण हैं। Alias full URL या host name से कम sensitive होता है और target selection को gateway configuration में स्पष्ट करने के लिए मजबूर करता है। अगर operator alias बदलता है, तो action check को दिखाना चाहिए कि किसी दूसरी जगह की testing चुपचाप शुरू होने से पहले configuration review जरूरी है।

Runner को नए agent process को approve करने की permission न दें। Per-session authorization default रूप से चालू होने का कारण है। नए agent process की पहली call approval card में उसकी code-signing authority दिखाती है और approval केवल उस run तक रहती है। Scheduled checks के लिए व्यक्ति से approval मिलने के बाद long-lived, reviewed health-client process रखें। Process exit होने पर अगली run में फिर approval मांगने की अपेक्षा करें।

यह hidden always-approved automation account से थोड़ा कम सुविधाजनक है। साथ ही, कोई नया executable केवल health check की command line copy कर लेने से permission हासिल नहीं कर पाता।

## Failed check को उपयोगी diagnosis चाहिए

Gateway health failures में अधिकतर साधारण configuration drift होती है। खतरा इस बात में है कि लोग broken boundary खोजने के बजाय controls कमजोर करके जवाब देते हैं।

एक वास्तविक जैसी स्थिति देखें। App चल रही है। Vault unlocked है। HTTP canary `401` लौटाती है। पहला विचार canary token को shell में paste करके endpoint को सीधे call करने का आता है। ऐसा न करें। इससे token के काम करने का प्रमाण तो मिलता है, लेकिन vault bypass होता है और secret leak का नया रास्ता बनता है।

इसके बजाय evidence को इस क्रम में देखें:

1. Confirm करें कि local MCP adapter gateway तक पहुंचा और submission से पहले timeout होने के बजाय action result मिला।
2. Confirm करें कि target alias अभी भी intended stored credential और endpoint configuration चुनता है।
3. Opaque request ID, method, route और rejection reason के लिए canary service logs देखें। Received authorization value log न करें।
4. Matching action attempt के लिए activity journal देखें और `sp audit verify` से audit chain verify करें।
5. अगर configuration review से expected value बदलने या expose होने का पता चले, तो canary credential rotate करें।

यह sequence चार ऐसी failures को अलग करता है जो अन्यथा एक जैसी दिखती हैं: गलत target mapping, revoked या rotated secret, gateway injection failure और upstream service configuration change। इससे वह आम self-inflicted incident भी टलता है जिसमें operator terminal में secret «test» करता है और फिर वह shell history, scrollback buffer या support bundle में copied मिलता है।

Severity को उस control के आधार पर classify करें जो fail हुआ। Unavailable app availability issue है। Locked vault द्वारा action deny करना informational है, जब तक scheduled approved check अपेक्षित न हो। Vault locked report होने के बावजूद canary action सफल होना security incident है। Broken audit chain भी security incident है, भले दोनों canary targets success लौटाएं।

इन categories को एक red या green badge के पीछे न छिपाएं। `vault=locked`, `audit=verified` और `http=skipped` देखने वाले operator को ठीक पता है कि क्या करना है। `health=warning` देखने वाला operator अनुमान लगाने लगता है।

## सबसे छोटी उपयोगी schedule में दो lanes होती हैं

Non-secret checks बार-बार चलाएं, फिर credentialed canary actions कम और सोच-समझकर चलाएं। दो lanes कम noise और बेहतर evidence देती हैं।

Unattended lane तब चल सकती है जब Mac के awake रहने की अपेक्षा हो। यह जांचती है कि app मौजूद है, locked vault lock रहते action deny करता है, MCP path classified response दे सकता है और `sp audit verify` पास होता है। इनमें से किसी check के लिए credential निकालने या vault unlock करने की जरूरत नहीं होनी चाहिए।

Credentialed lane vault unlock करने और जरूरत होने पर health-client session approve करने के बाद चलती है। यह एक HTTP canary action और एक SSH canary action करती है, remote receipts की पुष्टि करती है, संबंधित local activity records देखती है और audit chain फिर verify करती है। Modest cadence रखें। हर credentialed action audit event और remote service event बन जाती है, इसलिए हर minute check चलाने से confidence बहुत नहीं बढ़ता, noise जरूर बढ़ता है।

Credential configuration, target aliases, agent tooling, macOS permissions, network controls या gateway app में बदलाव के बाद credentialed lane चलाएं। इससे उन changes का पता चलता है जिनसे action execution टूटने की सबसे अधिक संभावना होती है। Reviewer को स्पष्ट before-and-after record भी मिलता है।

मानक सरल है: Health suite को उन controls को साबित करना चाहिए जिन पर आप निर्भर रहने वाले हैं। अगर वह केवल यह साबित कर सकती है कि menu bar में app icon अभी मौजूद है, तो उसे availability probe कहें और वहीं रुक जाएं। इसे autonomous agents के सुरक्षित ढंग से action करने का प्रमाण न कहें।
