Three plans covering Docker scaffold, SQLite schema, and .intunewin spike. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8.3 KiB
8.3 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 01-foundation | 03 | execute | 1 |
|
true |
|
|
Purpose: Validate the highest-risk unknown in the project — can Python generate a .intunewin file that Intune accepts? This spike runs independently of the web app and produces a standalone generator module reused in Phase 5. Supports INFRA-02 (no external binary dependencies like IntuneWinAppUtil.exe). Output: A tested build_intunewin() function and comprehensive byte-level validation tests.
<execution_context> @C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md @C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/01-foundation/01-CONTEXT.md @.planning/phases/01-foundation/01-RESEARCH.md Task 1: Implement .intunewin builder with byte-level tests imptune/generators/__init__.py, imptune/generators/intunewin_builder.py, tests/test_intunewin.py - test_output_is_valid_zip: build_intunewin() output file is a valid ZIP archive - test_outer_zip_structure: outer ZIP contains exactly IntuneWinPackage/Contents/IntunePackage.intunewin and IntuneWinPackage/Metadata/Detection.xml - test_outer_zip_stored: outer ZIP entries use ZIP_STORED compression (no extra compression on encrypted content) - test_detection_xml_valid: Detection.xml is valid XML with ApplicationInfo root element in the correct namespace (http://schemas.microsoft.com/IntuneWin) - test_detection_xml_fields: Detection.xml contains Name, UnencryptedContentSize, FileName, SetupFile, and full EncryptionInfo with all 8 sub-elements (EncryptionKey, MacKey, InitializationVector, Mac, MacAlgorithm, ProfileIdentifier, FileDigest, FileDigestAlgorithm) - test_encrypted_blob_layout: the encrypted blob starts with 32 bytes (HMAC) + 16 bytes (IV) + remainder (ciphertext); total length = 48 + ciphertext length - test_iv_is_16_bytes: IV extracted from Detection.xml base64-decodes to exactly 16 bytes (NOT 32 — critical per RESEARCH.md) - test_encryption_key_is_32_bytes: EncryptionKey from Detection.xml base64-decodes to exactly 32 bytes - test_mac_key_is_32_bytes: MacKey from Detection.xml base64-decodes to exactly 32 bytes - test_hmac_matches: HMAC-SHA256 computed from MacKey over ciphertext matches the first 32 bytes of the blob AND the Mac value in Detection.xml - test_decryption_roundtrip: using EncryptionKey and IV from Detection.xml, decrypt the ciphertext, unpad, and verify the result is a valid DEFLATE-compressed ZIP containing the original source files - test_file_digest_matches: FileDigest in Detection.xml matches SHA256 of the decrypted plaintext ZIP - test_unencrypted_content_size: UnencryptedContentSize in Detection.xml matches the byte length of the decrypted plaintext ZIP - test_setup_file_in_detection_xml: SetupFile element matches the setup_file argument passed to build_intunewin **imptune/generators/intunewin_builder.py**: Implement build_intunewin(source_dir: str, setup_file: str, output_path: str) -> None following the skeleton from RESEARCH.md Pattern 3, with these specifics:1. Create inner ZIP (DEFLATE compression) of all files in source_dir, preserving relative paths
2. Generate random keys: aes_key = os.urandom(32), mac_key = os.urandom(32), iv = os.urandom(16) — IV MUST be 16 bytes per the critical correction in RESEARCH.md
3. Encrypt with AES-256-CBC: cipher = AES.new(aes_key, AES.MODE_CBC, iv), ciphertext = cipher.encrypt(pad(plaintext, AES.block_size))
4. Compute HMAC-SHA256 of ciphertext using mac_key
5. Assemble encrypted blob: hmac_digest (32 bytes) + iv (16 bytes) + ciphertext
6. Compute file_digest = SHA256 of plaintext (the inner ZIP bytes before encryption)
7. Build Detection.xml with all required fields (see RESEARCH.md for exact schema). Use xml.etree.ElementTree for building and xml.dom.minidom for pretty printing. Set xmlns="http://schemas.microsoft.com/IntuneWin" on ApplicationInfo root.
8. Build outer ZIP (STORED compression) with two entries: IntuneWinPackage/Contents/IntunePackage.intunewin (the encrypted blob) and IntuneWinPackage/Metadata/Detection.xml
9. All base64 values in Detection.xml use standard base64 encoding (base64.b64encode)
**tests/test_intunewin.py**:
- Create a tmp_path fixture with a small test source directory (2-3 small text files, one named "install.ps1")
- Call build_intunewin(source_dir, "install.ps1", output_path) to generate the file
- Implement all tests from the behavior list above
- For the decryption roundtrip: extract EncryptionKey and IV from Detection.xml, use AES.new(key, AES.MODE_CBC, iv) to decrypt, unpad the result, verify it's a valid ZIP containing the original files
- For HMAC verification: extract MacKey from Detection.xml, compute hmac.new(mac_key, ciphertext, hashlib.sha256).digest(), compare to first 32 bytes of blob AND to Mac value in Detection.xml
The tests serve as the format specification — if they pass, the byte layout is correct. The only remaining validation is a real Intune upload (manual, Phase 5 gate).
<success_criteria>
- build_intunewin() produces a file with the exact byte layout Intune expects
- All crypto operations use correct key/IV sizes (32/32/16 bytes)
- HMAC and decryption roundtrip verified programmatically
- Detection.xml contains all 8 EncryptionInfo sub-elements with correct values
- Module is standalone — no dependency on the web framework or database </success_criteria>