# पुराने evidence को सुरक्षित रखने वाले audit format upgrades

ऑडिट format upgrade तभी सुरक्षित है जब investigator कल export किए गए evidence को उन rules से verify कर सके, जो कल लागू थे। नया parser सही दिखने वाला screen बनाए, database migration सफल हो और deployment हरा दिखे, इससे यह साबित नहीं होता। अक्सर असली समस्या छिप जाती है: record के bytes वही रहते हैं, लेकिन उसका अर्थ, hash input या verifier का व्यवहार बदल जाता है।

ऑडिट format को लंबे समय तक चलने वाले protocol की तरह समझें। आपका application हर सप्ताह बदल सकता है, evidence नहीं। जब कोई व्यक्ति किसी record पर यह समझने के लिए निर्भर करता है कि किसने कार्रवाई मंजूर की, कौन सा credential इस्तेमाल हुआ या agent ने external service को क्या भेजा, तो उस record की व्याख्या उस code के खत्म हो जाने के बाद भी स्थिर रहनी चाहिए जिसने उसे लिखा था।

## सुविधा से पहले bytes सुरक्षित रखें

Authoritative artifact मूल record byte sequence और उसे verify करने के लिए जरूरी context है। मौजूदा database में parsed row काम की copy है। Dashboard में दिखाया गया JSON object एक view है। Signature, hash chain या authenticated envelope में शामिल evidence bytes का स्थान इनमें से कोई नहीं ले सकता।

यह अंतर तब साफ होता है जब upgrade किसी field को rewrite कर देता है। मान लें version 1 में SSH target user-supplied string के रूप में रखा गया था:

```json
{"schema_version":1,"event":"ssh.execute","target":"build@prod.example:22","command":"uptime"}
```

Version 2 host और port पर filter करने के लिए अलग fields चाहता है:

```json
{"schema_version":2,"event":"ssh.execute","user":"build","host":"prod.example","port":22,"command":"uptime"}
```

दोनों records एक ही कार्रवाई का वर्णन कर सकते हैं, लेकिन वे interchangeable evidence नहीं हैं। V2 encoder hostname को normalize कर सकता है, default port जोड़ सकता है या ऐसा target अस्वीकार कर सकता है जिसे v1 स्वीकार करता था। पहले record को दूसरे से overwrite करने पर आपने पुराने event के बारे में नया दावा बना दिया। दावा सही हो सकता है, लेकिन rewritten data दिखाकर यह साबित नहीं किया जा सकता।

इन तीन चीजों को अलग रखें:

- **Original evidence**: audit sequence में स्वीकार किए गए bytes, बिल्कुल उसी रूप में और अपरिवर्तनीय।
- **Derived representation**: search और display के लिए indexed, decoded या migrated रूप।
- **Interpretation notes**: fields, defaults और version-specific behavior समझाने वाले documented rules।

Derived representation फिर से बनाई जा सकती है, original evidence नहीं। Originals को append-only evidence bundle या object store में रखें, digest से address करें और हर derived item को उस digest से जोड़ें। Retention rules के कारण deletion जरूरी हो तो उसे अपने event के रूप में record करें। इतिहास को चुपचाप compact करके उसे upgrade न कहें।

यह encrypted records वाले logs पर भी लागू होता है। Encryption content को unauthorized readers से बचाता है, लेकिन lossy migration को सुरक्षित नहीं बनाता। Verifier को अब भी पता होना चाहिए कि कौन सा ciphertext, header और chain rule परिणाम तक पहुंचा।

## हर record को स्पष्ट version दें

Hash या sign करने से पहले हर record के भीतर explicit `schema_version` रखें। Version को file extension, database migration number, application release या हाल में जोड़े गए field से infer न करें।

Inference पहले forensic export तक ठीक लगता है। Investigator को backup, support ticket या ऐसी machine से copied records का folder मिलता है, जो अब current app नहीं चलाती। आसपास का context अधूरा होता है, record मौजूद रहता है। अपना version रखने वाला record verifier को बताता है कि किस decoder और rules की जरूरत है।

जिस format के rules आपके नियंत्रण में हों, उसके लिए छोटा integer इस्तेमाल करें। Version 0 को invalid रखें, ताकि missing field चुपचाप legacy format न बन जाए। Version का काम सीमित रखें: record grammar और verification recipe चुनना। इसे सामान्य product release identifier न बनाएं।

एक टिकाऊ envelope इस तरह दिख सकता है:

```json
{
  "schema_version": 3,
  "record_id": "01J8X7K5W3H0Q9M6P2R4A1C8ZD",
  "recorded_at": "2026-07-22T14:08:31.482Z",
  "kind": "http.request.completed",
  "previous_digest": "sha256:4a4d...",
  "payload": {
    "method": "POST",
    "authority": "api.example.test",
    "status": 201
  }
}
```

Version authenticated input में शामिल होना चाहिए। यदि record version 3 कहता है, लेकिन digest उस field के बिना निकाला गया था, तो stored bytes बदल सकने वाला attacker verifier को अलग interpretation path पर भेज सकता है। Parser, hash algorithm, canonicalization rule या signature algorithm चुनने वाले हर field को protected bytes में शामिल करें।

**Record schema version** और **event meaning version** को भी अलग रखें। पहला पूछता है, «इन bytes को parse और verify कैसे करूं?» दूसरा पूछता है, «emit किए जाने के समय इस event का अर्थ क्या था?»

उदाहरण के लिए, `actor` को free-form display name से stable process identity में बदलने पर JSON shape वही रह सकती है, लेकिन दावा बदल जाता है। यह केवल schema version 4 नहीं है। यह semantic change है। Evidence specification में यह लिखा होना चाहिए कि नया अर्थ कब से लागू होता है। यही चेतावनी तब भी लागू होती है जब field की units बदलें, timestamp local time से UTC हो जाए या status observed response से policy decision बन जाए।

## केवल fields नहीं, verification recipe भी freeze करें

Versioned schema अधूरा है यदि verifier record को authenticate करने के लिए इस्तेमाल हुई exact byte recipe को फिर से नहीं बना सकता। Field layout उस recipe का केवल एक भाग है।

हर version के लिए लिखें:

- स्वीकार्य record grammar और required fields;
- text या binary encoding और canonicalization rules;
- digest और signature algorithms;
- domain separator, यदि इस्तेमाल हो;
- chain linking rule और genesis rule;
- malformed या unknown input पर failure behavior।

RFC 8785 बताता है कि cryptographic operations से पहले JSON को deterministic representation की जरूरत क्यों होती है। सामान्य JSON में एक ही logical value को कई तरह से serialize किया जा सकता है, जबकि hashing और signing के लिए invariant bytes चाहिए। उसका JSON Canonicalization Scheme input को सीमित करता है और object properties को deterministic तरीके से sort करता है। Format restrictions यह भी स्पष्ट करती हैं कि duplicate property names और supported representation से बाहर के numbers मामूली बातें नहीं हैं।

यह standard तभी उपयोगी है जब आप exact profile का नाम दें। «हम JSON hash करते हैं» कोई recipe नहीं है। «हम current runtime का serializer चलाते हैं» इससे भी खराब है, क्योंकि runtime upgrade escaping, numeric formatting या ordering बदल सकता है।

Binary formats में भी यही समस्या आती है। RFC 8949 CBOR के लिए deterministic encoding requirements बताता है और कहता है कि पिछली ordering convention के लिए compatibility mode का स्पष्ट नाम होना चाहिए। Verifier यह मानकर नहीं चल सकता कि हर historical producer ने «canonical» का एक ही अर्थ लिया था।

ऐसा नया verifier न बनाएं जो कोई भी JSON parse करे, आज की library से फिर serialize करे और फिर hash निकाले। इससे पुराना evidence दो तरह से टूट सकता है। वह पुराने recipe के तहत valid records को reject कर सकता है और नए recipe के तहत ऐसा record स्वीकार कर सकता है, जिसने original digest कभी बनाया ही नहीं।

इसके बजाय version dispatch को byte boundary के पास रखें:

```text
read envelope bytes
  -> identify protected schema_version
  -> select verifier V1, V2, or V3
  -> validate that version's grammar
  -> reproduce that version's authenticated bytes
  -> verify digest, signature, and chain link
  -> decode a display model only after verification
```

Display model को अंत में रखना जानबूझकर है। Renderer सुविधाजनक हो सकता है। Verifier कल्पना नहीं कर सकता।

## Unknown versions पर fail closed करें

जिस version को verifier support नहीं करता, उसके सामने स्पष्ट `unsupported_version` result लौटना चाहिए। Unknown fields को ignore न करें, latest layout न मानें और generic fallback decoder न चलाएं।

Forward compatibility की इच्छा समझ में आती है। Optional presentation fields पढ़ने वाले application के लिए यह उचित है। Evidence verification में यह खतरनाक है, क्योंकि optional दिखने वाला field बाद में authenticated interpretation को नियंत्रित कर सकता है।

ऐसा result shape रखें जो evidence failure और tool limitation को अलग करे:

```json
{
  "record_id": "01J8X7K5W3H0Q9M6P2R4A1C8ZD",
  "schema_version": 4,
  "status": "unsupported_version",
  "verified": false,
  "supported_versions": [1, 2, 3],
  "reason": "Verifier 2.7.0 has no verification recipe for schema version 4"
}
```

इसका अर्थ सटीक है: tool ने authenticity स्थापित नहीं की है। यह record पर tampering का आरोप नहीं लगाता और उसे valid भी नहीं बताता। Command output और APIs दोनों में `invalid`, `incomplete`, `unsupported_version` और `verified` अलग रखें।

Hash chain के साथ एक और compatibility requirement जुड़ती है। Chain history को केवल अंतिम digest से नहीं समझा जा सकता। Verifier को पहले record, record ordering, parent digest encoding और checkpoint format के version-specific rules चाहिए। Certificate Transparency का mental model उपयोगी है: RFC 9162 consistency proofs को परिभाषित करता है, जो दिखाते हैं कि पुराना tree नए tree का वही prefix है, न कि auditors को नए root hash पर भरोसा करने को कहते हैं।

आपकी audit sequence Merkle tree न भी हो, lesson वही है। Chain rules बदलने पर boundary पर continuity साबित करें। अंतिम verified digest, record count और version वाला terminal v1 checkpoint बनाएं। पहला v2 record उस checkpoint को defined field में authenticate करे। V2 verifier को continuous history बताने से पहले दोनों sides को अपने-अपने rules से verify करना चाहिए।

दो histories को comment या display field में पुराना digest रखकर कभी न जोड़ें। Join protected input का हिस्सा होना चाहिए।

## Migrations derivatives बनाएं, replacements नहीं

अच्छी migration source evidence के पास नया, reproducible derivative बनाती है। उसमें इतना provenance हो कि कोई दूसरा व्यक्ति वही output फिर बना सके और source से तुलना कर सके।

हर migrated record या batch के लिए यह जानकारी रखें:

```json
{
  "source_digest": "sha256:4a4d...",
  "source_schema_version": 1,
  "migration_id": "audit-v1-to-v2",
  "migration_build": "2.7.0+e31c9f4",
  "output_digest": "sha256:77c8...",
  "migrated_at": "2026-07-22T14:12:09Z"
}
```

`migrated_at` derivative का समय बताता है, original event का नहीं। `recorded_at` को overwrite न करें और generated v2 record को ऐसा न दिखाएं जैसे वह पुराने system ने emit किया हो। Internal investigations में यह गलती किसी साफ parser crash से ज्यादा भ्रम पैदा कर सकती है।

कुछ migrations lossless नहीं हो सकतीं। V1 record में एक `target` string हो सकती है, जबकि v2 structured URI मांगता है। Parsing fail हो या ambiguity हो तो source string सुरक्षित रखें और explicit migration status record करें। केवल इसलिए structured value न गढ़ें कि नए index को वह चाहिए।

उदाहरण:

```json
{
  "source_digest": "sha256:4a4d...",
  "migration_status": "partial",
  "derived": {
    "target_raw": "build@prod.example:22",
    "host": "prod.example",
    "port": 22
  },
  "unresolved": ["user"]
}
```

यह fully populated row जितना साफ-सुथरा नहीं दिखता, लेकिन अधिक ईमानदार है। Future investigator देख सकता है कि पुराने record ने क्या कहा था और migration ने क्या अनुमान लगाया।

हर पुराने entry को current writer से चलाकर upgrade कहने की सलाह से बचें। इससे एक code path सरल होता है और reports एक जैसी दिखती हैं, इसलिए यह लोकप्रिय है। Evidence के लिए यह गलत है, क्योंकि writers current defaults लागू करते हैं, पुराने fields छोड़ते हैं और values normalize करते हैं। Output search के लिए उपयोगी हो सकता है, लेकिन वह translation है, original testimony नहीं।

## Permanent fixture corpus शांत टूटनों को पकड़ता है

Compatibility test asset है, release note का वादा नहीं। हर released schema version के लिए evidence corpus बनाएं और हर उस verifier build पर चलाएं जो उस version का support बताता है।

Corpus में कुछ happy-path records ही पर्याप्त नहीं हैं। इन cases के byte-exact fixtures रखें:

- सामान्य valid record और valid multi-record chain;
- boundary timestamps, Unicode text, empty optional values और उस version द्वारा स्वीकार numeric limits;
- बदले हुए payload byte वाला record;
- बदले हुए parent digest या reordered sequence वाला record;
- malformed, duplicate, truncated और unknown-version input।

केवल decoded objects नहीं, expected outcomes भी रखें। Test को evidence result और diagnostic category दोनों पर assert करना चाहिए। Valid record को invalid mark करने वाला verifier भी fail हुआ है। Malformed record को generic parser exception में बदलना कम नाटकीय failure है, लेकिन investigation को कठिन बनाता है।

Fixture digests और expected verifier behavior pin करने वाला manifest रखें:

```yaml
fixture: v1/0007-http-request.json
sha256: 4a4d5f0c...
expect:
  status: verified
  schema_version: 1
  chain_position: 7

fixture: v1/0007-http-request-tampered.json
sha256: 91af2a7d...
expect:
  status: invalid
  error_code: payload_digest_mismatch
```

दोनों दिशाओं में test करें:

1. सबसे पुराना retained verifier अपने original corpus को अब भी verify करे।
2. Current verifier हर retained historical corpus को verify करे।
3. Candidate writer ऐसे records बनाए जिन्हें current verifier नए version के तहत स्वीकार करे।
4. Candidate migration अपना stated source digest सुरक्षित रखे और अपेक्षित derivative बनाए।
5. हर verifier unsupported future versions के लिए बने fixtures को reject करे।

Test fail होने पर expected fixtures को तुरंत rewrite न करें। पहले bytes, चुने गए verifier version और failure code देखें। Fixture updates दुर्लभ हों, protocol change की तरह review हों और यह कारण दें कि नया fixture जानबूझकर बनाया गया है या evidence बदला है।

Parsers के आसपास property testing जोड़ें, लेकिन इसे permanent corpus न समझें। Random input crashes और अजीब edge cases खोजता है। Named fixtures उन कठिन सीखों को सुरक्षित रखते हैं, जिनमें sensitive content हटाने के बाद real releases के records भी शामिल हो सकते हैं।

## Upgrade boundary को investigation की तरह test करें

सबसे बड़ा risk आमतौर पर versions की boundary पर होता है, किसी एक version के भीतर नहीं। ऐसा scenario लिखें जो upgrade से पहले शुरू होकर बाद में खत्म हो और पूछे कि क्या independent व्यक्ति पूरी sequence समझ सकता है।

मान लें chain में v1 agent session approval, कई HTTP calls और session revoke record करता है। Version 2 अधिक detailed request result field और नया checksum encoding लाता है। Test v1 genesis record से शुरू हो, valid v1 entries जोड़े, documented boundary checkpoint बनाए, v2 entries जोड़े और पूरा bundle export करे।

Expected verification report transition को साफ दिखाए:

```text
$ audit verify evidence-bundle
verified v1 records: 18
verified v1 terminal digest: sha256:6c12...e98a
verified v1-to-v2 continuity checkpoint
verified v2 records: 6
chain status: verified
```

फिर production upgrades से पैदा होने वाली failures चलाएं:

- अंतिम v1 record हटाएं और v2 records रहने दें;
- checkpoint का v1 digest बदलें;
- v1 version label वाला v2 record इस्तेमाल करें;
- केवल v2 segment export करके full-history verdict मांगें;
- mixed bundle पर pre-v2 verifier चलाएं।

सही system अलग-अलग उत्तर देगा। पहले तीन invalid हैं। चौथा partial segment के रूप में verify हो सकता है, यदि bundle अपना starting checkpoint घोषित करता हो, लेकिन वह full history verify होने का दावा नहीं कर सकता। पांचवां, यदि command partial reports की अनुमति देती है, तो जितने v1 evidence को verify कर सके उतना report करने के बाद `unsupported_version` लौटाएगा। पूरे bundle को verified नहीं बताना चाहिए।

यहीं teams को पता चलता है कि journals और dashboards source boundaries छिपा रहे हैं। UI records को एक timeline में मिला सकती है, बशर्ते schema transition label करे और reviewer को original envelope देखने दे। Investigator को अचानक field दिखने से format change का अनुमान लगाने पर मजबूर न करें।

## Verifier को application से अधिक टिकाऊ बनाएं

Audit verifier के dependencies और privileges records बनाने वाले application से कम होने चाहिए। पुराने evidence को पढ़ने के लिए graphical application शुरू करना, account से connect होना, credential vault खोलना या compatibility package download करना पड़े, तो evidence plan उन परिस्थितियों पर निर्भर है जो सबसे खराब समय पर गायब हो सकती हैं।

जिम्मेदारियां अलग रखें:

- Application records लिखता है और live activity दिखाता है।
- Compact verifier exported bundle पढ़ता है, versioned recipes चुनता है और machine-readable report देता है।
- Renderer verified records को tables और timelines में बदल सकता है, बिना authenticity decision में भाग लिए।

Verifier deterministic बनाएं। एक ही bundle और command options पर status codes और report structure समान आने चाहिए। Report में verifier release identifier शामिल करें, लेकिन उसे evidence result बदलने न दें।

Sallyport के लिए upgrade runbook में `sp audit verify` को बनाए रखना सही check है, क्योंकि यह ciphertext पर encrypted hash chain को offline verify करता है और vault key की जरूरत नहीं होती। App बदलने से पहले untouched export के पास command की report save करें, फिर upgrade के बाद उसी export को दोबारा verify करें।

«Offline» शब्द का अर्थ स्पष्ट रखें। इसका मतलब है कि verifier उपलब्ध evidence और built-in verification recipes से chain result स्थापित कर सकता है। इसका मतलब यह नहीं कि वह missing records फिर बना सकता है, यह तय कर सकता है कि machine किसने चलाया या साबित कर सकता है कि user ने approval card समझा। अच्छी report ठीक-ठीक बताती है कि कौन सा claim check हुआ।

Evidence format specification को verifier source और fixtures के साथ publish करें। Fixture corpus के बिना source release future maintainers को compatibility के बारे में अनुमान लगाने पर छोड़ देता है। लिखित recipe के बिना corpus यह नहीं बताता कि passing test deliberate rule का परिणाम है या किसी implementation का संयोग।

## पहली emergency से पहले retirement policy तय करें

Historical format का support तभी बंद करें जब तय कर लें कि उसे इस्तेमाल करने वाले evidence के साथ क्या होगा। यह निर्णय security, legal, operations और incident investigators का होना चाहिए। पुराने package को delete करने का incidental परिणाम नहीं।

Support table लिखें जिसमें retained versions, उन्हें पढ़ सकने वाले verifier releases, expected evidence retention period और exceptional archive की प्रक्रिया हो। Reader retire करना हो तो पहले standalone archive verifier दें और उसका fixture corpus freeze करें। Build instructions और expected checksums evidence documentation के साथ रखें।

Perpetual support का वादा सहजता से न करें। Algorithms पुराने होते हैं, operating systems बदलते हैं और पुराने parsers में security defects हो सकते हैं। फिर भी retained evidence verify करने का रास्ता बचा रहना चाहिए। कभी sandboxed archive tool पर्याप्त होगा जो केवल local files लेता है। कभी recorded hashes के साथ container या virtual machine image रखना होगा। चुनाव environment पर निर्भर है, लेकिन future investigator से vanished toolchain को याद से फिर बनाने की अपेक्षा नहीं करनी चाहिए।

पहली कार्रवाई स्पष्ट है: छोटा real evidence bundle export करें, verifier चलाएं और command पर निर्भर हर versioned rule लिखें। यदि test upgrade के बाद उस recipe को बता और परिणाम को reproduce नहीं कर सकते, तो आपके पास अभी upgrade plan नहीं है। आपके पास केवल यह उम्मीद है कि पुराना evidence पढ़ने योग्य रहेगा।
