Attachment "stageA-record.tar" to
tech note [bae6999eb9]
added by
opus-ocx2
2026-10-28 22:51:50.
0000: 73 74 61 67 65 41 2d 72 65 63 6f 72 64 2f 00 00 stageA-record/..
0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0060: 00 00 00 00 30 30 30 30 37 35 35 00 30 30 30 30 ....0000755.0000
0070: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
0080: 30 30 30 30 30 30 30 00 31 35 32 37 30 34 37 36 0000000.15270476
0090: 32 30 35 00 30 31 32 32 34 34 00 20 35 00 00 00 205.012244. 5...
00a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0100: 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
0110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0120: 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
0130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
01f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0200: 73 74 61 67 65 41 2d 72 65 63 6f 72 64 2f 72 65 stageA-record/re
0210: 63 6f 72 64 2e 74 78 74 00 00 00 00 00 00 00 00 cord.txt........
0220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0260: 00 00 00 00 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000
0270: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
0280: 30 30 31 35 36 33 34 00 31 35 32 37 30 34 37 36 0015634.15270476
0290: 32 30 35 00 30 31 34 32 37 34 00 20 30 00 00 00 205.014274. 0...
02a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0300: 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
0310: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0320: 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
0330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
03a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
03b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
03c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
03d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
03e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
03f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0400: 0a 3d 3d 20 62 75 69 6c 64 3a 20 73 74 61 72 74 .== build: start
0410: 2d 6f 63 78 2c 20 72 65 63 65 69 70 74 73 20 61 -ocx, receipts a
0420: 6e 64 20 6f 63 78 32 20 66 72 6f 6d 20 2f 76 61 nd ocx2 from /va
0430: 72 2f 6c 69 62 2f 6f 63 78 2f 61 67 65 6e 74 73 r/lib/ocx/agents
0440: 2f 6f 70 75 73 2d 6f 63 78 32 2f 70 72 6f 6a 65 /opus-ocx2/proje
0450: 63 74 73 2f 6f 6c 6c 61 6d 61 2f 62 32 64 65 38 cts/ollama/b2de8
0460: 62 30 63 32 63 36 37 30 30 65 62 35 63 36 38 36 b0c2c6700eb5c686
0470: 62 31 37 34 37 62 35 61 61 61 31 65 32 64 32 64 b1747b5aaa1e2d2d
0480: 30 31 33 37 30 61 63 35 35 66 32 65 35 61 31 35 01370ac55f2e5a15
0490: 31 61 36 37 65 30 33 62 34 38 61 2f 74 72 65 65 1a67e03b48a/tree
04a0: 38 0a 0a 3d 3d 20 73 65 72 76 65 64 20 72 65 70 8..== served rep
04b0: 6f 73 69 74 6f 72 79 3a 20 64 65 6d 6f 2e 66 6f ository: demo.fo
04c0: 73 73 69 6c 2c 20 75 73 65 72 73 2c 20 63 68 61 ssil, users, cha
04d0: 74 20 74 69 6d 65 6c 69 6e 65 0a 2d 72 77 2d 2d t timeline.-rw--
04e0: 2d 2d 2d 2d 2d 20 20 20 20 31 20 72 6f 6f 74 20 ----- 1 root
04f0: 20 20 20 20 72 6f 6f 74 20 20 20 20 20 20 20 20 root
0500: 32 31 37 30 38 38 20 4f 63 74 20 32 38 20 32 32 217088 Oct 28 22
0510: 3a 34 35 20 2f 74 6d 70 2f 73 41 2d 33 35 32 39 :45 /tmp/sA-3529
0520: 33 35 32 2f 66 6f 73 73 69 6c 2f 64 65 6d 6f 2e 352/fossil/demo.
0530: 66 6f 73 73 69 6c 0a 0a 3d 3d 20 72 65 63 65 69 fossil..== recei
0540: 70 74 20 73 65 72 76 69 63 65 2c 20 74 68 72 6f pt service, thro
0550: 75 67 68 20 74 68 65 20 6c 61 75 6e 63 68 65 72 ugh the launcher
0560: 27 73 20 72 65 63 65 69 70 74 73 20 70 6f 6c 69 's receipts poli
0570: 63 79 0a 74 6f 74 61 6c 20 30 0a 73 72 77 2d 2d cy.total 0.srw--
0580: 2d 2d 2d 2d 2d 20 20 20 20 31 20 72 6f 6f 74 20 ----- 1 root
0590: 20 20 20 20 72 6f 6f 74 20 20 20 20 20 20 20 20 root
05a0: 20 20 20 20 20 30 20 4f 63 74 20 32 38 20 32 32 0 Oct 28 22
05b0: 3a 34 35 20 72 65 63 65 69 70 74 73 2e 73 6f 63 :45 receipts.soc
05c0: 6b 0a 0a 3d 3d 20 46 6f 73 73 69 6c 20 73 65 72 k..== Fossil ser
05d0: 76 65 72 2c 20 69 74 73 20 65 78 74 72 6f 6f 74 ver, its extroot
05e0: 27 73 20 6f 63 78 32 2d 63 67 69 20 74 68 65 20 's ocx2-cgi the
05f0: 6c 61 75 6e 63 68 65 72 0a 0a 3d 3d 20 74 68 65 launcher..== the
0600: 20 64 61 65 6d 6f 6e 27 73 20 6e 6f 64 65 3a 20 daemon's node:
0610: 6e 6f 64 65 73 2e 6a 73 6f 6e 20 61 6e 64 20 63 nodes.json and c
0620: 72 65 64 65 6e 74 69 61 6c 73 0a 0a 3d 3d 20 63 redentials..== c
0630: 6f 6e 66 69 6e 65 64 20 64 61 65 6d 6f 6e 2c 20 onfined daemon,
0640: 74 68 72 6f 75 67 68 20 74 68 65 20 6c 61 75 6e through the laun
0650: 63 68 65 72 27 73 20 64 61 65 6d 6f 6e 20 70 6f cher's daemon po
0660: 6c 69 63 79 0a 7b 22 77 68 65 6e 22 3a 22 32 30 licy.{"when":"20
0670: 32 36 2d 31 30 2d 32 38 54 32 32 3a 34 36 3a 34 26-10-28T22:46:4
0680: 37 5a 22 2c 22 63 6c 6f 6e 65 22 3a 22 2f 74 6d 7Z","clone":"/tm
0690: 70 2f 73 41 2d 33 35 32 39 33 35 32 2f 64 61 65 p/sA-3529352/dae
06a0: 6d 6f 6e 2f 6e 6f 64 65 2f 63 6c 6f 6e 65 73 2f mon/node/clones/
06b0: 64 65 6d 6f 2e 66 6f 73 73 69 6c 22 2c 22 63 6f demo.fossil","co
06c0: 6d 70 6c 65 74 69 6f 6e 22 3a 31 2c 22 6e 65 77 mpletion":1,"new
06d0: 22 3a 30 2c 22 68 61 6e 64 65 64 22 3a 5b 5d 2c ":0,"handed":[],
06e0: 22 73 65 74 74 6c 65 64 22 3a 30 7d 0a 7b 22 77 "settled":0}.{"w
06f0: 68 65 6e 22 3a 22 32 30 32 36 2d 31 30 2d 32 38 hen":"2026-10-28
0700: 54 32 32 3a 34 36 3a 35 30 5a 22 2c 22 63 6c 6f T22:46:50Z","clo
0710: 6e 65 22 3a 22 2f 74 6d 70 2f 73 41 2d 33 35 32 ne":"/tmp/sA-352
0720: 39 33 35 32 2f 64 61 65 6d 6f 6e 2f 6e 6f 64 65 9352/daemon/node
0730: 2f 63 6c 6f 6e 65 73 2f 64 65 6d 6f 2e 66 6f 73 /clones/demo.fos
0740: 73 69 6c 22 2c 22 63 6f 6d 70 6c 65 74 69 6f 6e sil","completion
0750: 22 3a 31 2c 22 6e 65 77 22 3a 30 2c 22 68 61 6e ":1,"new":0,"han
0760: 64 65 64 22 3a 5b 5d 2c 22 73 65 74 74 6c 65 64 ded":[],"settled
0770: 22 3a 30 7d 0a 7b 22 77 68 65 6e 22 3a 22 32 30 ":0}.{"when":"20
0780: 32 36 2d 31 30 2d 32 38 54 32 32 3a 34 36 3a 35 26-10-28T22:46:5
0790: 34 5a 22 2c 22 63 6c 6f 6e 65 22 3a 22 2f 74 6d 4Z","clone":"/tm
07a0: 70 2f 73 41 2d 33 35 32 39 33 35 32 2f 64 61 65 p/sA-3529352/dae
07b0: 6d 6f 6e 2f 6e 6f 64 65 2f 63 6c 6f 6e 65 73 2f mon/node/clones/
07c0: 64 65 6d 6f 2e 66 6f 73 73 69 6c 22 2c 22 63 6f demo.fossil","co
07d0: 6d 70 6c 65 74 69 6f 6e 22 3a 31 2c 22 6e 65 77 mpletion":1,"new
07e0: 22 3a 30 2c 22 68 61 6e 64 65 64 22 3a 5b 5d 2c ":0,"handed":[],
07f0: 22 73 65 74 74 6c 65 64 22 3a 30 7d 0a 0a 3d 3d "settled":0}..==
0800: 20 74 77 6f 20 72 75 6e 73 2c 20 70 6f 73 74 65 two runs, poste
0810: 64 20 62 79 20 62 6f 73 73 20 28 73 65 74 75 70 d by boss (setup
0820: 29 20 74 68 72 6f 75 67 68 20 46 6f 73 73 69 6c ) through Fossil
0830: 27 73 20 66 6f 72 6d 0a 73 61 6e 64 62 6f 78 65 's form.sandboxe
0840: 64 20 72 75 6e 20 65 35 39 66 61 35 66 30 34 66 d run e59fa5f04f
0850: 0a 75 6e 63 6f 6e 66 69 6e 65 64 20 72 75 6e 20 .unconfined run
0860: 61 38 32 65 64 34 63 36 39 62 0a 0a 3d 3d 20 77 a82ed4c69b..== w
0870: 68 61 74 20 74 68 65 20 72 75 6e 73 20 70 6f 73 hat the runs pos
0880: 74 65 64 20 28 73 74 61 72 74 65 64 2c 20 6b 65 ted (started, ke
0890: 70 74 20 6c 6f 67 73 2c 20 65 6e 64 65 64 29 0a pt logs, ended).
08a0: 27 65 35 39 66 61 35 66 30 34 66 27 2c 27 62 6f 'e59fa5f04f','bo
08b0: 73 73 27 2c 27 44 20 32 30 32 36 2d 31 30 2d 32 ss','D 2026-10-2
08c0: 38 54 32 32 3a 34 36 3a 35 36 2e 31 37 36 20 48 8T22:46:56.176 H
08d0: 20 73 61 6e 64 62 6f 78 65 64 5c 73 70 72 6f 62 sandboxed\sprob
08e0: 65 20 4e 20 74 65 78 74 2f 78 2d 6d 61 72 6b 64 e N text/x-markd
08f0: 6f 77 6e 20 55 20 62 6f 73 73 20 57 20 31 30 30 own U boss W 100
0900: 37 20 60 60 60 6a 73 6f 6e 20 7b 22 6f 63 78 22 7 ```json {"ocx"
0910: 3a 20 31 2c 20 22 6b 69 6e 64 22 3a 20 22 72 75 : 1, "kind": "ru
0920: 6e 22 2c 20 22 6e 6f 64 65 22 3a 20 22 64 65 6d n", "node": "dem
0930: 6f 2d 6e 6f 64 65 22 2c 20 22 6f 62 6a 65 63 74 o-node", "object
0940: 69 76 65 22 3a 20 22 50 72 6f 62 65 20 66 72 6f ive": "Probe fro
0950: 6d 20 61 6e 20 61 67 65 6e 74 20 73 61 6e 64 62 m an agent sandb
0960: 6f 78 2e 22 2c 20 22 77 6f 72 6b 73 70 61 63 65 ox.", "workspace
0970: 22 3a 20 5b 7b 22 73 74 65 70 22 3a 20 22 64 69 ": [{"step": "di
0980: 72 65 63 74 6f 72 79 22 2c 20 22 61 74 22 3a 20 rectory", "at":
0990: 22 24 24 72 6f 6f 74 24 24 2f 24 24 75 73 65 72 "$$root$$/$$user
09a0: 24 24 2f 70 72 6f 6a 65 63 74 73 2f 24 24 70 72 $$/projects/$$pr
09b0: 6f 6a 65 63 74 24 24 2f 24 24 72 75 6e 24 24 22 oject$$/$$run$$"
09c0: 7d 5d 2c 20 22 73 61 6e 64 62 6f 78 22 3a 20 7b }], "sandbox": {
09d0: 22 75 69 64 22 3a 20 31 30 30 30 2c 20 22 67 69 "uid": 1000, "gi
09e0: 64 22 3a 20 31 30 30 30 2c 20 22 63 61 70 61 62 d": 1000, "capab
09f0: 69 6c 69 74 69 65 73 22 3a 20 5b 5d 2c 20 22 6e ilities": [], "n
0a00: 65 74 77 6f 72 6b 22 3a 20 66 61 6c 73 65 2c 20 etwork": false,
0a10: 22 6f 77 6e 5f 73 65 73 73 69 6f 6e 22 3a 20 74 "own_session": t
0a20: 72 75 65 2c 20 22 65 6e 64 73 5f 77 69 74 68 5f rue, "ends_with_
0a30: 6e 6f 64 65 22 3a 20 74 72 75 65 2c 20 22 72 65 node": true, "re
0a40: 61 64 5f 6f 6e 6c 79 22 3a 20 5b 22 2f 75 73 72 ad_only": ["/usr
0a50: 22 2c 20 22 2f 62 69 6e 22 2c 20 22 2f 6c 69 62 ", "/bin", "/lib
0a60: 22 2c 20 22 2f 6c 69 62 36 34 22 5d 2c 20 22 72 ", "/lib64"], "r
0a70: 65 61 64 5f 77 72 69 74 65 22 3a 20 5b 22 24 24 ead_write": ["$$
0a80: 77 6f 72 6b 73 70 61 63 65 24 24 22 5d 2c 20 22 workspace$$"], "
0a90: 68 6f 6d 65 73 22 3a 20 5b 5d 2c 20 22 66 69 6c homes": [], "fil
0aa0: 65 73 22 3a 20 5b 5d 2c 20 22 70 72 6f 63 22 3a es": [], "proc":
0ab0: 20 22 2f 70 72 6f 63 22 2c 20 22 64 65 76 22 3a "/proc", "dev":
0ac0: 20 22 2f 64 65 76 22 2c 20 22 74 6d 70 22 3a 20 "/dev", "tmp":
0ad0: 22 2f 74 6d 70 22 7d 2c 20 22 6c 69 6d 69 74 73 "/tmp"}, "limits
0ae0: 22 3a 20 7b 22 77 61 6c 6c 22 3a 20 22 32 6d 22 ": {"wall": "2m"
0af0: 7d 2c 20 22 70 72 6f 63 65 73 73 22 3a 20 7b 22 }, "process": {"
0b00: 75 73 65 72 22 3a 20 22 62 75 69 6c 64 27 0a 27 user": "build'.'
0b10: 61 38 32 65 64 34 63 36 39 62 27 2c 27 62 6f 73 a82ed4c69b','bos
0b20: 73 27 2c 27 44 20 32 30 32 36 2d 31 30 2d 32 38 s','D 2026-10-28
0b30: 54 32 32 3a 34 36 3a 35 36 2e 32 37 39 20 48 20 T22:46:56.279 H
0b40: 75 6e 63 6f 6e 66 69 6e 65 64 5c 73 70 72 6f 62 unconfined\sprob
0b50: 65 20 4e 20 74 65 78 74 2f 78 2d 6d 61 72 6b 64 e N text/x-markd
0b60: 6f 77 6e 20 55 20 62 6f 73 73 20 57 20 36 34 32 own U boss W 642
0b70: 20 60 60 60 6a 73 6f 6e 20 7b 22 6f 63 78 22 3a ```json {"ocx":
0b80: 20 31 2c 20 22 6b 69 6e 64 22 3a 20 22 72 75 6e 1, "kind": "run
0b90: 22 2c 20 22 6e 6f 64 65 22 3a 20 22 64 65 6d 6f ", "node": "demo
0ba0: 2d 6e 6f 64 65 22 2c 20 22 6f 62 6a 65 63 74 69 -node", "objecti
0bb0: 76 65 22 3a 20 22 50 72 6f 62 65 20 66 72 6f 6d ve": "Probe from
0bc0: 20 74 68 65 20 64 61 65 6d 6f 6e 20 69 74 73 65 the daemon itse
0bd0: 6c 66 2c 20 75 6e 63 6f 6e 66 69 6e 65 64 20 62 lf, unconfined b
0be0: 79 20 61 6e 79 20 72 75 6e 20 73 61 6e 64 62 6f y any run sandbo
0bf0: 78 2e 22 2c 20 22 70 72 6f 63 65 73 73 22 3a 20 x.", "process":
0c00: 7b 22 75 73 65 72 22 3a 20 22 62 75 69 6c 64 65 {"user": "builde
0c10: 72 22 2c 20 22 63 6f 6d 6d 61 6e 64 22 3a 20 5b r", "command": [
0c20: 22 2f 62 69 6e 2f 73 68 22 2c 20 22 2d 63 22 2c "/bin/sh", "-c",
0c30: 20 22 65 63 68 6f 20 75 69 64 3d 24 28 69 64 20 "echo uid=$(id
0c40: 2d 75 29 3b 20 66 6f 72 20 70 20 69 6e 20 2f 74 -u); for p in /t
0c50: 6d 70 2f 73 41 2d 33 35 32 39 33 35 32 2f 66 6f mp/sA-3529352/fo
0c60: 73 73 69 6c 20 2f 74 6d 70 2f 73 41 2d 33 35 32 ssil /tmp/sA-352
0c70: 39 33 35 32 2f 66 6f 73 73 69 6c 2f 64 65 6d 6f 9352/fossil/demo
0c80: 2e 66 6f 73 73 69 6c 3b 20 64 6f 20 5b 20 2d 65 .fossil; do [ -e
0c90: 20 24 70 20 5d 20 26 26 20 65 63 68 6f 20 56 49 $p ] && echo VI
0ca0: 53 49 42 4c 45 20 24 70 20 7c 7c 20 65 63 68 6f SIBLE $p || echo
0cb0: 20 61 62 73 65 6e 74 20 24 70 3b 20 64 6f 6e 65 absent $p; done
0cc0: 3b 20 68 65 61 64 20 2d 63 20 31 36 20 2f 74 6d ; head -c 16 /tm
0cd0: 70 2f 73 41 2d 33 35 32 39 33 35 32 2f 66 6f 73 p/sA-3529352/fos
0ce0: 73 69 6c 2f 64 65 6d 6f 2e 66 6f 73 73 69 6c 20 sil/demo.fossil
0cf0: 3e 2f 64 65 76 2f 6e 75 6c 6c 20 32 3e 26 31 20 >/dev/null 2>&1
0d00: 26 26 20 65 63 68 6f 20 52 45 41 44 2d 4f 4b 20 && echo READ-OK
0d10: 7c 7c 20 65 63 68 6f 20 72 65 61 64 2d 72 65 66 || echo read-ref
0d20: 75 73 65 64 3b 20 6e 3d 30 3b 20 66 6f 72 20 78 used; n=0; for x
0d30: 20 69 6e 20 2f 70 72 6f 63 2f 5b 30 2d 39 5d 2a in /proc/[0-9]*
0d40: 2f 72 6f 6f 74 2f 74 6d 70 2f 73 41 2d 33 35 32 /root/tmp/sA-352
0d50: 39 33 35 32 2f 66 6f 73 73 69 6c 2f 64 65 6d 6f 9352/fossil/demo
0d60: 2e 66 6f 73 73 69 6c 3b 20 64 6f 20 5b 20 2d 72 .fossil; do [ -r
0d70: 20 24 78 20 5d 20 26 26 20 6e 3d 24 27 0a 27 62 $x ] && n=$'.'b
0d80: 62 31 64 32 36 63 39 30 36 27 2c 27 64 65 6d 6f b1d26c906','demo
0d90: 2d 6e 6f 64 65 27 2c 27 44 20 32 30 32 36 2d 31 -node','D 2026-1
0da0: 30 2d 32 38 54 32 32 3a 34 36 3a 35 37 2e 35 30 0-28T22:46:57.50
0db0: 32 20 47 20 61 38 32 65 64 34 63 36 39 62 64 61 2 G a82ed4c69bda
0dc0: 61 39 33 64 65 33 64 33 36 39 34 30 39 31 38 39 a93de3d369409189
0dd0: 65 66 38 38 39 64 30 39 64 61 39 65 37 64 37 64 ef889d09da9e7d7d
0de0: 31 64 66 65 39 63 30 61 37 33 37 36 38 31 65 65 1dfe9c0a737681ee
0df0: 61 62 38 35 20 49 20 61 38 32 65 64 34 63 36 39 ab85 I a82ed4c69
0e00: 62 64 61 61 39 33 64 65 33 64 33 36 39 34 30 39 bdaa93de3d369409
0e10: 31 38 39 65 66 38 38 39 64 30 39 64 61 39 65 37 189ef889d09da9e7
0e20: 64 37 64 31 64 66 65 39 63 30 61 37 33 37 36 38 d7d1dfe9c0a73768
0e30: 31 65 65 61 62 38 35 20 4e 20 74 65 78 74 2f 78 1eeab85 N text/x
0e40: 2d 6d 61 72 6b 64 6f 77 6e 20 55 20 64 65 6d 6f -markdown U demo
0e50: 2d 6e 6f 64 65 20 57 20 32 37 37 20 60 60 60 6a -node W 277 ```j
0e60: 73 6f 6e 20 7b 20 20 22 6f 63 78 22 3a 20 31 2c son { "ocx": 1,
0e70: 20 20 22 6b 69 6e 64 22 3a 20 22 65 6e 64 65 64 "kind": "ended
0e80: 22 2c 20 20 22 6e 6f 64 65 22 3a 20 22 64 65 6d ", "node": "dem
0e90: 6f 2d 6e 6f 64 65 22 2c 20 20 22 63 6c 6f 6e 65 o-node", "clone
0ea0: 22 3a 20 22 61 63 39 39 36 30 65 37 34 35 36 66 ": "ac9960e7456f
0eb0: 32 31 30 37 34 62 35 63 62 38 32 35 32 33 61 30 21074b5cb82523a0
0ec0: 35 35 62 63 65 33 66 64 63 37 36 37 22 2c 20 20 55bce3fdc767",
0ed0: 22 72 75 6e 22 3a 20 22 61 38 32 65 64 34 63 36 "run": "a82ed4c6
0ee0: 39 62 64 61 61 39 33 64 65 33 64 33 36 39 34 30 9bdaa93de3d36940
0ef0: 39 31 38 39 65 66 38 38 39 64 30 39 64 61 39 65 9189ef889d09da9e
0f00: 37 64 37 64 31 64 66 65 39 63 30 61 37 33 37 36 7d7d1dfe9c0a7376
0f10: 38 31 65 65 61 62 38 35 22 2c 20 20 22 6f 75 74 81eeab85", "out
0f20: 63 6f 6d 65 22 3a 20 22 72 65 66 75 73 65 64 22 come": "refused"
0f30: 2c 20 20 22 6e 6f 74 65 22 3a 20 22 74 68 69 73 , "note": "this
0f40: 20 6e 6f 64 65 20 72 75 6e 73 20 6f 6e 6c 79 20 node runs only
0f50: 73 61 6e 64 62 6f 78 65 64 20 70 72 6f 63 65 73 sandboxed proces
0f60: 73 65 73 22 20 7d 20 60 60 60 20 5a 20 38 31 32 ses" } ``` Z 812
0f70: 64 36 36 65 36 34 65 64 34 37 38 35 33 61 63 39 d66e64ed47853ac9
0f80: 33 33 31 66 34 66 66 63 64 34 37 39 33 20 27 0a 331f4ffcd4793 '.
0f90: 27 39 66 66 66 32 38 61 66 30 64 27 2c 27 64 65 '9fff28af0d','de
0fa0: 6d 6f 2d 6e 6f 64 65 27 2c 27 44 20 32 30 32 36 mo-node','D 2026
0fb0: 2d 31 30 2d 32 38 54 32 32 3a 34 36 3a 35 38 2e -10-28T22:46:58.
0fc0: 35 30 38 20 47 20 65 35 39 66 61 35 66 30 34 66 508 G e59fa5f04f
0fd0: 39 66 64 62 66 34 61 36 39 30 30 64 35 61 35 37 9fdbf4a6900d5a57
0fe0: 31 31 65 38 61 62 63 36 30 64 64 63 61 32 38 62 11e8abc60ddca28b
0ff0: 37 65 36 33 32 66 64 37 36 63 36 32 30 63 37 36 7e632fd76c620c76
1000: 35 35 36 30 35 62 20 49 20 65 35 39 66 61 35 66 55605b I e59fa5f
1010: 30 34 66 39 66 64 62 66 34 61 36 39 30 30 64 35 04f9fdbf4a6900d5
1020: 61 35 37 31 31 65 38 61 62 63 36 30 64 64 63 61 a5711e8abc60ddca
1030: 32 38 62 37 65 36 33 32 66 64 37 36 63 36 32 30 28b7e632fd76c620
1040: 63 37 36 35 35 36 30 35 62 20 4e 20 74 65 78 74 c7655605b N text
1050: 2f 78 2d 6d 61 72 6b 64 6f 77 6e 20 55 20 64 65 /x-markdown U de
1060: 6d 6f 2d 6e 6f 64 65 20 57 20 36 38 37 20 60 60 mo-node W 687 ``
1070: 60 6a 73 6f 6e 20 7b 20 20 22 6f 63 78 22 3a 20 `json { "ocx":
1080: 31 2c 20 20 22 6b 69 6e 64 22 3a 20 22 73 74 61 1, "kind": "sta
1090: 72 74 65 64 22 2c 20 20 22 6e 6f 64 65 22 3a 20 rted", "node":
10a0: 22 64 65 6d 6f 2d 6e 6f 64 65 22 2c 20 20 22 63 "demo-node", "c
10b0: 6c 6f 6e 65 22 3a 20 22 61 63 39 39 36 30 65 37 lone": "ac9960e7
10c0: 34 35 36 66 32 31 30 37 34 62 35 63 62 38 32 35 456f21074b5cb825
10d0: 32 33 61 30 35 35 62 63 65 33 66 64 63 37 36 37 23a055bce3fdc767
10e0: 22 2c 20 20 22 72 75 6e 22 3a 20 22 65 35 39 66 ", "run": "e59f
10f0: 61 35 66 30 34 66 39 66 64 62 66 34 61 36 39 30 a5f04f9fdbf4a690
1100: 30 64 35 61 35 37 31 31 65 38 61 62 63 36 30 64 0d5a5711e8abc60d
1110: 64 63 61 32 38 62 37 65 36 33 32 66 64 37 36 63 dca28b7e632fd76c
1120: 36 32 30 63 37 36 35 35 36 30 35 62 22 2c 20 20 620c7655605b",
1130: 22 76 61 6c 75 65 73 22 3a 20 7b 20 20 20 22 72 "values": { "r
1140: 6f 6f 74 22 3a 20 22 2f 74 6d 70 2f 73 41 2d 33 oot": "/tmp/sA-3
1150: 35 32 39 33 35 32 2f 64 61 65 6d 6f 6e 2f 61 67 529352/daemon/ag
1160: 65 6e 74 73 22 2c 20 20 20 22 70 72 6f 6a 65 63 ents", "projec
1170: 74 22 3a 20 22 64 65 6d 6f 22 2c 20 20 20 22 75 t": "demo", "u
1180: 73 65 72 22 3a 20 22 62 75 69 6c 64 65 72 22 2c ser": "builder",
1190: 20 20 20 22 72 75 6e 22 3a 20 22 65 35 39 66 61 "run": "e59fa
11a0: 35 66 30 34 66 39 66 64 62 66 34 61 36 39 30 30 5f04f9fdbf4a6900
11b0: 64 35 61 35 37 31 31 65 38 61 62 63 36 30 64 64 d5a5711e8abc60dd
11c0: 63 61 32 38 62 37 65 36 33 32 66 64 37 36 63 36 ca28b7e632fd76c6
11d0: 32 30 63 37 36 35 35 36 30 35 62 22 2c 20 20 20 20c7655605b",
11e0: 22 6e 6f 64 65 22 3a 20 22 64 65 6d 6f 2d 6e 6f "node": "demo-no
11f0: 64 65 22 2c 20 20 20 22 73 65 72 76 65 72 22 3a de", "server":
1200: 20 22 27 0a 27 31 65 38 37 31 31 35 32 35 66 27 "'.'1e8711525f'
1210: 2c 27 64 65 6d 6f 2d 6e 6f 64 65 27 2c 27 44 20 ,'demo-node','D
1220: 32 30 32 36 2d 31 30 2d 32 38 54 32 32 3a 34 36 2026-10-28T22:46
1230: 3a 35 38 2e 35 39 30 20 47 20 65 35 39 66 61 35 :58.590 G e59fa5
1240: 66 30 34 66 39 66 64 62 66 34 61 36 39 30 30 64 f04f9fdbf4a6900d
1250: 35 61 35 37 31 31 65 38 61 62 63 36 30 64 64 63 5a5711e8abc60ddc
1260: 61 32 38 62 37 65 36 33 32 66 64 37 36 63 36 32 a28b7e632fd76c62
1270: 30 63 37 36 35 35 36 30 35 62 20 49 20 65 35 39 0c7655605b I e59
1280: 66 61 35 66 30 34 66 39 66 64 62 66 34 61 36 39 fa5f04f9fdbf4a69
1290: 30 30 64 35 61 35 37 31 31 65 38 61 62 63 36 30 00d5a5711e8abc60
12a0: 64 64 63 61 32 38 62 37 65 36 33 32 66 64 37 36 ddca28b7e632fd76
12b0: 63 36 32 30 63 37 36 35 35 36 30 35 62 20 4e 20 c620c7655605b N
12c0: 74 65 78 74 2f 78 2d 6d 61 72 6b 64 6f 77 6e 20 text/x-markdown
12d0: 55 20 64 65 6d 6f 2d 6e 6f 64 65 20 57 20 32 33 U demo-node W 23
12e0: 32 20 54 68 65 20 70 72 6f 63 65 73 73 20 66 6f 2 The process fo
12f0: 72 20 74 68 65 20 72 75 6e 20 65 35 39 66 61 35 r the run e59fa5
1300: 66 30 34 66 39 66 64 62 66 34 61 36 39 30 30 64 f04f9fdbf4a6900d
1310: 35 61 35 37 31 31 65 38 61 62 63 36 30 64 64 63 5a5711e8abc60ddc
1320: 61 32 38 62 37 65 36 33 32 66 64 37 36 63 36 32 a28b7e632fd76c62
1330: 30 63 37 36 35 35 36 30 35 62 20 65 78 69 74 65 0c7655605b exite
1340: 64 20 30 2e 20 7e 7e 7e 7e 20 73 74 64 6f 75 74 d 0. ~~~~ stdout
1350: 20 75 69 64 3d 31 30 30 30 20 61 62 73 65 6e 74 uid=1000 absent
1360: 20 2f 74 6d 70 2f 73 41 2d 33 35 32 39 33 35 32 /tmp/sA-3529352
1370: 2f 66 6f 73 73 69 6c 20 61 62 73 65 6e 74 20 2f /fossil absent /
1380: 74 6d 70 2f 73 41 2d 33 35 32 39 33 35 32 2f 66 tmp/sA-3529352/f
1390: 6f 73 73 69 6c 2f 64 65 6d 6f 2e 66 6f 73 73 69 ossil/demo.fossi
13a0: 6c 20 72 65 61 64 2d 72 65 66 75 73 65 64 20 70 l read-refused p
13b0: 72 6f 63 2d 70 61 74 68 73 2d 72 65 61 64 61 62 roc-paths-readab
13c0: 6c 65 3d 30 20 7e 7e 7e 7e 20 5a 20 32 38 32 33 le=0 ~~~~ Z 2823
13d0: 31 34 36 61 31 34 38 37 36 30 35 62 33 65 35 61 146a1487605b3e5a
13e0: 35 37 38 61 38 38 33 66 63 32 35 61 20 27 0a 27 578a883fc25a '.'
13f0: 37 32 35 61 31 32 35 65 65 38 27 2c 27 64 65 6d 725a125ee8','dem
1400: 6f 2d 6e 6f 64 65 27 2c 27 44 20 32 30 32 36 2d o-node','D 2026-
1410: 31 30 2d 32 38 54 32 32 3a 34 36 3a 35 38 2e 36 10-28T22:46:58.6
1420: 30 30 20 47 20 65 35 39 66 61 35 66 30 34 66 39 00 G e59fa5f04f9
1430: 66 64 62 66 34 61 36 39 30 30 64 35 61 35 37 31 fdbf4a6900d5a571
1440: 31 65 38 61 62 63 36 30 64 64 63 61 32 38 62 37 1e8abc60ddca28b7
1450: 65 36 33 32 66 64 37 36 63 36 32 30 63 37 36 35 e632fd76c620c765
1460: 35 36 30 35 62 20 49 20 65 35 39 66 61 35 66 30 5605b I e59fa5f0
1470: 34 66 39 66 64 62 66 34 61 36 39 30 30 64 35 61 4f9fdbf4a6900d5a
1480: 35 37 31 31 65 38 61 62 63 36 30 64 64 63 61 32 5711e8abc60ddca2
1490: 38 62 37 65 36 33 32 66 64 37 36 63 36 32 30 63 8b7e632fd76c620c
14a0: 37 36 35 35 36 30 35 62 20 4e 20 74 65 78 74 2f 7655605b N text/
14b0: 78 2d 6d 61 72 6b 64 6f 77 6e 20 55 20 64 65 6d x-markdown U dem
14c0: 6f 2d 6e 6f 64 65 20 57 20 32 33 36 20 60 60 60 o-node W 236 ```
14d0: 6a 73 6f 6e 20 7b 20 20 22 6f 63 78 22 3a 20 31 json { "ocx": 1
14e0: 2c 20 20 22 6b 69 6e 64 22 3a 20 22 65 6e 64 65 , "kind": "ende
14f0: 64 22 2c 20 20 22 6e 6f 64 65 22 3a 20 22 64 65 d", "node": "de
1500: 6d 6f 2d 6e 6f 64 65 22 2c 20 20 22 63 6c 6f 6e mo-node", "clon
1510: 65 22 3a 20 22 61 63 39 39 36 30 65 37 34 35 36 e": "ac9960e7456
1520: 66 32 31 30 37 34 62 35 63 62 38 32 35 32 33 61 f21074b5cb82523a
1530: 30 35 35 62 63 65 33 66 64 63 37 36 37 22 2c 20 055bce3fdc767",
1540: 20 22 72 75 6e 22 3a 20 22 65 35 39 66 61 35 66 "run": "e59fa5f
1550: 30 34 66 39 66 64 62 66 34 61 36 39 30 30 64 35 04f9fdbf4a6900d5
1560: 61 35 37 31 31 65 38 61 62 63 36 30 64 64 63 61 a5711e8abc60ddca
1570: 32 38 62 37 65 36 33 32 66 64 37 36 63 36 32 30 28b7e632fd76c620
1580: 63 37 36 35 35 36 30 35 62 22 2c 20 20 22 6f 75 c7655605b", "ou
1590: 74 63 6f 6d 65 22 3a 20 22 65 78 69 74 65 64 22 tcome": "exited"
15a0: 2c 20 20 22 65 78 69 74 22 3a 20 30 20 7d 20 60 , "exit": 0 } `
15b0: 60 60 20 5a 20 65 61 36 65 64 36 61 39 62 63 39 `` Z ea6ed6a9bc9
15c0: 31 30 31 34 35 38 62 63 66 36 62 39 66 61 39 65 101458bcf6b9fa9e
15d0: 39 63 36 39 30 20 27 0a 0a 3d 3d 20 72 65 63 65 9c690 '..== rece
15e0: 69 70 74 73 20 74 68 72 6f 75 67 68 20 74 68 65 ipts through the
15f0: 20 6c 61 75 6e 63 68 65 72 27 73 20 43 47 49 20 launcher's CGI
1600: 72 6f 75 74 65 2c 20 61 67 61 69 6e 73 74 20 46 route, against F
1610: 6f 73 73 69 6c 27 73 20 6f 77 6e 20 72 65 63 6f ossil's own reco
1620: 72 64 0a 62 6f 73 73 20 7b 22 61 72 74 69 66 61 rd.boss {"artifa
1630: 63 74 73 22 3a 20 5b 7b 22 61 72 74 69 66 61 63 cts": [{"artifac
1640: 74 22 3a 20 22 65 35 39 66 61 35 66 30 34 66 39 t": "e59fa5f04f9
1650: 66 64 62 66 34 61 36 39 30 30 64 35 61 35 37 31 fdbf4a6900d5a571
1660: 31 65 38 61 62 63 36 30 64 64 63 61 32 38 62 37 1e8abc60ddca28b7
1670: 65 36 33 32 66 64 37 36 63 36 32 30 63 37 36 35 e632fd76c620c765
1680: 35 36 30 35 62 22 2c 20 22 72 65 63 65 69 76 65 5605b", "receive
1690: 64 22 3a 20 74 72 75 65 2c 20 22 73 65 6e 64 65 d": true, "sende
16a0: 72 22 3a 20 22 62 6f 73 73 22 2c 20 22 63 61 70 r": "boss", "cap
16b0: 61 62 69 6c 69 74 69 65 73 22 3a 20 22 62 63 64 abilities": "bcd
16c0: 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 efghijklmnopqrst
16d0: 77 7a 32 33 34 35 36 37 41 44 22 2c 20 22 72 65 wz234567AD", "re
16e0: 63 65 69 70 74 22 3a 20 32 2c 20 22 72 69 64 22 ceipt": 2, "rid"
16f0: 3a 20 32 7d 5d 2c 20 22 75 73 65 72 22 3a 20 7b : 2}], "user": {
1700: 22 75 73 65 72 22 3a 20 22 64 65 6d 6f 2d 6e 6f "user": "demo-no
1710: 64 65 22 2c 20 22 63 61 70 61 62 69 6c 69 74 69 de", "capabiliti
1720: 65 73 22 3a 20 22 67 68 6a 6f 72 77 7a 34 43 22 es": "ghjorwz4C"
1730: 2c 20 22 77 69 6b 69 5f 6d 6f 64 65 72 61 74 65 , "wiki_moderate
1740: 64 22 3a 20 66 61 6c 73 65 2c 20 22 74 69 63 6b d": false, "tick
1750: 65 74 5f 6d 6f 64 65 72 61 74 65 64 22 3a 20 66 et_moderated": f
1760: 61 6c 73 65 7d 7d 0a 76 69 65 77 65 72 20 7b 22 alse}}.viewer {"
1770: 61 72 74 69 66 61 63 74 73 22 3a 20 5b 7b 22 61 artifacts": [{"a
1780: 72 74 69 66 61 63 74 22 3a 20 22 65 35 39 66 61 rtifact": "e59fa
1790: 35 66 30 34 66 39 66 64 62 66 34 61 36 39 30 30 5f04f9fdbf4a6900
17a0: 64 35 61 35 37 31 31 65 38 61 62 63 36 30 64 64 d5a5711e8abc60dd
17b0: 63 61 32 38 62 37 65 36 33 32 66 64 37 36 63 36 ca28b7e632fd76c6
17c0: 32 30 63 37 36 35 35 36 30 35 62 22 2c 20 22 72 20c7655605b", "r
17d0: 65 63 65 69 76 65 64 22 3a 20 74 72 75 65 2c 20 eceived": true,
17e0: 22 73 65 6e 64 65 72 22 3a 20 22 62 6f 73 73 22 "sender": "boss"
17f0: 2c 20 22 63 61 70 61 62 69 6c 69 74 69 65 73 22 , "capabilities"
1800: 3a 20 22 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e : "bcdefghijklmn
1810: 6f 70 71 72 73 74 77 7a 32 33 34 35 36 37 41 44 opqrstwz234567AD
1820: 22 2c 20 22 72 65 63 65 69 70 74 22 3a 20 32 2c ", "receipt": 2,
1830: 20 22 72 69 64 22 3a 20 32 7d 5d 2c 20 22 75 73 "rid": 2}], "us
1840: 65 72 22 3a 20 7b 22 75 73 65 72 22 3a 20 22 64 er": {"user": "d
1850: 65 6d 6f 2d 6e 6f 64 65 22 2c 20 22 63 61 70 61 emo-node", "capa
1860: 62 69 6c 69 74 69 65 73 22 3a 20 22 67 68 6a 6f bilities": "ghjo
1870: 72 77 7a 34 43 22 2c 20 22 77 69 6b 69 5f 6d 6f rwz4C", "wiki_mo
1880: 64 65 72 61 74 65 64 22 3a 20 66 61 6c 73 65 2c derated": false,
1890: 20 22 74 69 63 6b 65 74 5f 6d 6f 64 65 72 61 74 "ticket_moderat
18a0: 65 64 22 3a 20 66 61 6c 73 65 7d 7d 0a 61 6e 6f ed": false}}.ano
18b0: 6e 20 7b 22 61 72 74 69 66 61 63 74 73 22 3a 20 n {"artifacts":
18c0: 5b 7b 22 61 72 74 69 66 61 63 74 22 3a 20 22 65 [{"artifact": "e
18d0: 35 39 66 61 35 66 30 34 66 39 66 64 62 66 34 61 59fa5f04f9fdbf4a
18e0: 36 39 30 30 64 35 61 35 37 31 31 65 38 61 62 63 6900d5a5711e8abc
18f0: 36 30 64 64 63 61 32 38 62 37 65 36 33 32 66 64 60ddca28b7e632fd
1900: 37 36 63 36 32 30 63 37 36 35 35 36 30 35 62 22 76c620c7655605b"
1910: 2c 20 22 72 65 63 65 69 76 65 64 22 3a 20 74 72 , "received": tr
1920: 75 65 2c 20 22 73 65 6e 64 65 72 22 3a 20 22 62 ue, "sender": "b
1930: 6f 73 73 22 2c 20 22 63 61 70 61 62 69 6c 69 74 oss", "capabilit
1940: 69 65 73 22 3a 20 22 62 63 64 65 66 67 68 69 6a ies": "bcdefghij
1950: 6b 6c 6d 6e 6f 70 71 72 73 74 77 7a 32 33 34 35 klmnopqrstwz2345
1960: 36 37 41 44 22 2c 20 22 72 65 63 65 69 70 74 22 67AD", "receipt"
1970: 3a 20 32 2c 20 22 72 69 64 22 3a 20 32 7d 5d 2c : 2, "rid": 2}],
1980: 20 22 75 73 65 72 22 3a 20 7b 22 75 73 65 72 22 "user": {"user"
1990: 3a 20 22 64 65 6d 6f 2d 6e 6f 64 65 22 2c 20 22 : "demo-node", "
19a0: 63 61 70 61 62 69 6c 69 74 69 65 73 22 3a 20 22 capabilities": "
19b0: 67 68 6a 6f 72 77 7a 34 43 22 2c 20 22 77 69 6b ghjorwz4C", "wik
19c0: 69 5f 6d 6f 64 65 72 61 74 65 64 22 3a 20 66 61 i_moderated": fa
19d0: 6c 73 65 2c 20 22 74 69 63 6b 65 74 5f 6d 6f 64 lse, "ticket_mod
19e0: 65 72 61 74 65 64 22 3a 20 66 61 6c 73 65 7d 7d erated": false}}
19f0: 0a 46 6f 73 73 69 6c 27 73 20 6f 77 6e 20 72 65 .Fossil's own re
1a00: 63 6f 72 64 3a 20 27 62 6f 73 73 27 2c 27 62 63 cord: 'boss','bc
1a10: 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 defghijklmnopqrs
1a20: 74 77 7a 32 33 34 35 36 37 41 44 27 2c 32 2c 32 twz234567AD',2,2
1a30: 0a 46 6f 73 73 69 6c 27 73 20 66 75 6c 6c 63 61 .Fossil's fullca
1a40: 70 28 64 65 6d 6f 2d 6e 6f 64 65 29 3a 20 27 67 p(demo-node): 'g
1a50: 68 6a 6f 72 77 7a 34 43 27 0a 0a 3d 3d 20 74 68 hjorwz4C'..== th
1a60: 65 20 63 6f 6e 73 6f 6c 65 2c 20 61 73 20 62 6f e console, as bo
1a70: 73 73 20 28 74 68 65 20 70 61 67 65 27 73 20 6f ss (the page's o
1a80: 74 68 65 72 20 70 61 74 68 73 20 73 74 69 6c 6c ther paths still
1a90: 20 70 61 73 73 20 74 68 72 6f 75 67 68 3a 20 45 pass through: E
1aa0: 36 29 0a 63 6f 6e 73 6f 6c 65 20 6f 6b 3a 20 54 6).console ok: T
1ab0: 72 75 65 20 7c 20 72 75 6e 73 20 72 75 6e 6e 69 rue | runs runni
1ac0: 6e 67 3a 20 30 20 7c 20 65 6e 64 65 64 3a 20 32 ng: 0 | ended: 2
1ad0: 0a 0a 3d 3d 20 77 72 69 74 65 73 20 66 72 6f 6d ..== writes from
1ae0: 20 74 68 65 20 72 65 63 65 69 70 74 20 73 65 72 the receipt ser
1af0: 76 69 63 65 27 73 20 70 6f 6c 69 63 79 20 66 61 vice's policy fa
1b00: 69 6c 20 28 61 20 70 72 6f 62 65 20 69 6e 20 70 il (a probe in p
1b10: 6c 61 63 65 20 6f 66 20 72 65 63 65 69 70 74 73 lace of receipts
1b20: 29 0a 46 6f 73 73 69 6c 27 73 20 70 6f 72 74 20 ).Fossil's port
1b30: 35 33 30 30 31 20 61 6e 73 77 65 72 73 20 6f 6e 53001 answers on
1b40: 20 74 68 65 20 68 6f 73 74 3a 20 32 30 30 0a 47 the host: 200.G
1b50: 43 20 57 61 72 6e 69 6e 67 3a 20 43 6f 75 6c 64 C Warning: Could
1b60: 20 6e 6f 74 20 6f 70 65 6e 20 2f 70 72 6f 63 2f not open /proc/
1b70: 73 74 61 74 0a 6f 70 65 6e 20 74 68 65 20 72 65 stat.open the re
1b80: 70 6f 73 69 74 6f 72 79 20 66 6f 72 20 77 72 69 pository for wri
1b90: 74 69 6e 67 3a 20 72 65 66 75 73 65 64 20 28 46 ting: refused (F
1ba0: 69 6c 65 3a 3a 45 72 72 6f 72 3a 20 45 72 72 6f ile::Error: Erro
1bb0: 72 20 6f 70 65 6e 69 6e 67 20 66 69 6c 65 20 77 r opening file w
1bc0: 69 74 68 20 6d 6f 64 65 20 27 72 2b 27 3a 20 27 ith mode 'r+': '
1bd0: 2f 74 6d 70 2f 73 41 2d 33 35 32 39 33 35 32 2f /tmp/sA-3529352/
1be0: 66 6f 73 73 69 6c 2f 64 65 6d 6f 2e 66 6f 73 73 fossil/demo.foss
1bf0: 69 6c 27 3a 20 52 65 61 64 2d 6f 6e 6c 79 20 66 il': Read-only f
1c00: 69 6c 65 20 73 79 73 74 65 6d 29 0a 63 72 65 61 ile system).crea
1c10: 74 65 20 61 20 66 69 6c 65 20 62 65 73 69 64 65 te a file beside
1c20: 20 69 74 3a 20 72 65 66 75 73 65 64 20 28 46 69 it: refused (Fi
1c30: 6c 65 3a 3a 45 72 72 6f 72 3a 20 45 72 72 6f 72 le::Error: Error
1c40: 20 6f 70 65 6e 69 6e 67 20 66 69 6c 65 20 77 69 opening file wi
1c50: 74 68 20 6d 6f 64 65 20 27 77 27 3a 20 27 2f 74 th mode 'w': '/t
1c60: 6d 70 2f 73 41 2d 33 35 32 39 33 35 32 2f 66 6f mp/sA-3529352/fo
1c70: 73 73 69 6c 2f 78 27 3a 20 52 65 61 64 2d 6f 6e ssil/x': Read-on
1c80: 6c 79 20 66 69 6c 65 20 73 79 73 74 65 6d 29 0a ly file system).
1c90: 72 65 61 64 20 74 68 65 20 72 65 70 6f 73 69 74 read the reposit
1ca0: 6f 72 79 3a 20 72 65 61 64 20 6f 6b 20 28 61 6c ory: read ok (al
1cb0: 6c 6f 77 65 64 3a 20 72 65 61 64 2d 6f 6e 6c 79 lowed: read-only
1cc0: 29 0a 72 65 61 63 68 20 46 6f 73 73 69 6c 27 73 ).reach Fossil's
1cd0: 20 70 6f 72 74 3a 20 72 65 66 75 73 65 64 20 28 port: refused (
1ce0: 53 6f 63 6b 65 74 3a 3a 43 6f 6e 6e 65 63 74 45 Socket::ConnectE
1cf0: 72 72 6f 72 3a 20 45 72 72 6f 72 20 63 6f 6e 6e rror: Error conn
1d00: 65 63 74 69 6e 67 20 74 6f 20 27 31 32 37 2e 30 ecting to '127.0
1d10: 2e 30 2e 31 3a 35 33 30 30 31 27 3a 20 43 6f 6e .0.1:53001': Con
1d20: 6e 65 63 74 69 6f 6e 20 72 65 66 75 73 65 64 29 nection refused)
1d30: 0a 77 72 69 74 65 20 69 6e 20 69 74 73 20 73 6f .write in its so
1d40: 63 6b 65 74 20 64 69 72 65 63 74 6f 72 79 3a 20 cket directory:
1d50: 77 72 69 74 74 65 6e 20 28 61 6c 6c 6f 77 65 64 written (allowed
1d60: 3a 20 69 74 73 20 6f 6e 65 20 77 72 69 74 61 62 : its one writab
1d70: 6c 65 20 70 6c 61 63 65 29 0a 0a 3d 3d 20 74 68 le place)..== th
1d80: 65 20 64 61 65 6d 6f 6e 27 73 20 6f 77 6e 20 76 e daemon's own v
1d90: 69 65 77 3a 20 61 20 70 72 6f 62 65 20 69 6e 20 iew: a probe in
1da0: 70 6c 61 63 65 20 6f 66 20 69 74 73 20 70 72 6f place of its pro
1db0: 67 72 61 6d 2c 20 73 74 61 72 74 65 64 20 74 68 gram, started th
1dc0: 72 6f 75 67 68 20 74 68 65 20 73 61 6d 65 20 64 rough the same d
1dd0: 61 65 6d 6f 6e 20 70 6f 6c 69 63 79 0a 64 61 65 aemon policy.dae
1de0: 6d 6f 6e 20 70 72 6f 62 65 3a 20 75 69 64 3d 30 mon probe: uid=0
1df0: 20 63 61 70 73 3d 43 61 70 45 66 66 3a 20 30 30 caps=CapEff: 00
1e00: 30 30 30 31 66 66 66 66 66 66 66 66 66 66 0a 61 0001ffffffffff.a
1e10: 62 73 65 6e 74 20 2f 74 6d 70 2f 73 41 2d 33 35 bsent /tmp/sA-35
1e20: 32 39 33 35 32 2f 66 6f 73 73 69 6c 0a 61 62 73 29352/fossil.abs
1e30: 65 6e 74 20 2f 74 6d 70 2f 73 41 2d 33 35 32 39 ent /tmp/sA-3529
1e40: 33 35 32 2f 66 6f 73 73 69 6c 2f 64 65 6d 6f 2e 352/fossil/demo.
1e50: 66 6f 73 73 69 6c 0a 70 72 6f 63 2d 70 61 74 68 fossil.proc-path
1e60: 73 2d 72 65 61 64 61 62 6c 65 3d 30 20 28 6f 74 s-readable=0 (ot
1e70: 68 65 72 20 70 72 6f 63 65 73 73 65 73 20 6f 66 her processes of
1e80: 20 74 68 65 20 73 61 6d 65 20 61 63 63 6f 75 6e the same accoun
1e90: 74 3b 20 74 68 65 20 6c 69 76 65 20 64 61 65 6d t; the live daem
1ea0: 6f 6e 20 68 61 73 20 61 6e 20 61 63 63 6f 75 6e on has an accoun
1eb0: 74 20 6f 66 20 69 74 73 20 6f 77 6e 29 0a 61 67 t of its own).ag
1ec0: 65 6e 74 20 73 61 6e 64 62 6f 78 20 69 6e 73 69 ent sandbox insi
1ed0: 64 65 3a 20 73 74 61 72 74 65 64 0a 0a 3d 3d 20 de: started..==
1ee0: 72 6f 6c 6c 62 61 63 6b 20 70 6f 69 6e 74 3a 20 rollback point:
1ef0: 74 68 65 20 6c 61 75 6e 63 68 65 72 27 73 20 43 the launcher's C
1f00: 47 49 20 6c 69 6e 6b 20 69 73 20 6f 6e 65 20 66 GI link is one f
1f10: 69 6c 65 3b 20 74 68 65 20 70 72 65 76 69 6f 75 ile; the previou
1f20: 73 20 70 61 67 65 20 69 73 20 74 68 65 20 72 65 s page is the re
1f30: 6c 65 61 73 65 27 73 20 6f 77 6e 20 6f 63 78 32 lease's own ocx2
1f40: 0a 2d 72 77 78 72 2d 78 72 2d 78 20 20 20 20 31 .-rwxr-xr-x 1
1f50: 20 72 6f 6f 74 20 20 20 20 20 72 6f 6f 74 20 20 root root
1f60: 20 20 20 20 20 20 20 20 20 31 39 37 20 4f 63 74 197 Oct
1f70: 20 32 38 20 32 32 3a 34 35 20 2f 74 6d 70 2f 73 28 22:45 /tmp/s
1f80: 41 2d 33 35 32 39 33 35 32 2f 65 78 74 2f 6f 63 A-3529352/ext/oc
1f90: 78 32 2d 63 67 69 0a 64 6f 6e 65 0a 00 00 00 00 x2-cgi.done.....
1fa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
1fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
1fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
1fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
1fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
1ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2000: 73 74 61 67 65 41 2d 72 65 63 6f 72 64 2f 70 72 stageA-record/pr
2010: 6f 62 65 2e 63 72 00 00 00 00 00 00 00 00 00 00 obe.cr..........
2020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2060: 00 00 00 00 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000
2070: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
2080: 30 30 30 31 36 36 37 00 31 35 32 37 30 34 37 36 0001667.15270476
2090: 32 30 35 00 30 31 33 37 31 33 00 20 30 00 00 00 205.013713. 0...
20a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
20b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
20c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
20d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
20e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
20f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2100: 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
2110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2120: 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
2130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
21a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
21b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
21c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
21d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
21e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
21f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2200: 72 65 71 75 69 72 65 20 22 73 6f 63 6b 65 74 22 require "socket"
2210: 0a 73 6f 63 6b 65 74 2c 20 64 69 72 20 3d 20 41 .socket, dir = A
2220: 52 47 56 0a 72 65 70 6f 20 3d 20 44 69 72 2e 63 RGV.repo = Dir.c
2230: 68 69 6c 64 72 65 6e 28 64 69 72 29 2e 66 69 6e hildren(dir).fin
2240: 64 28 26 2e 65 6e 64 73 5f 77 69 74 68 3f 28 22 d(&.ends_with?("
2250: 2e 66 6f 73 73 69 6c 22 29 29 2e 6e 6f 74 5f 6e .fossil")).not_n
2260: 69 6c 21 0a 70 61 74 68 20 3d 20 46 69 6c 65 2e il!.path = File.
2270: 6a 6f 69 6e 28 64 69 72 2c 20 72 65 70 6f 29 0a join(dir, repo).
2280: 74 72 69 65 73 20 3d 20 7b 0a 20 20 22 6f 70 65 tries = {. "ope
2290: 6e 20 74 68 65 20 72 65 70 6f 73 69 74 6f 72 79 n the repository
22a0: 20 66 6f 72 20 77 72 69 74 69 6e 67 22 20 3d 3e for writing" =>
22b0: 20 2d 3e 20 7b 20 46 69 6c 65 2e 6f 70 65 6e 28 -> { File.open(
22c0: 70 61 74 68 2c 20 22 72 2b 22 29 20 7b 20 7d 3b path, "r+") { };
22d0: 20 22 4f 50 45 4e 45 44 20 28 62 61 64 29 22 20 "OPENED (bad)"
22e0: 7d 2c 0a 20 20 22 63 72 65 61 74 65 20 61 20 66 },. "create a f
22f0: 69 6c 65 20 62 65 73 69 64 65 20 69 74 22 20 20 ile beside it"
2300: 20 20 20 20 20 20 20 3d 3e 20 2d 3e 20 7b 20 46 => -> { F
2310: 69 6c 65 2e 77 72 69 74 65 28 46 69 6c 65 2e 6a ile.write(File.j
2320: 6f 69 6e 28 64 69 72 2c 20 22 78 22 29 2c 20 22 oin(dir, "x"), "
2330: 78 22 29 3b 20 22 43 52 45 41 54 45 44 20 28 62 x"); "CREATED (b
2340: 61 64 29 22 20 7d 2c 0a 20 20 22 72 65 61 64 20 ad)" },. "read
2350: 74 68 65 20 72 65 70 6f 73 69 74 6f 72 79 22 20 the repository"
2360: 20 20 20 20 20 20 20 20 20 20 20 20 3d 3e 20 2d => -
2370: 3e 20 7b 20 46 69 6c 65 2e 6f 70 65 6e 28 70 61 > { File.open(pa
2380: 74 68 29 20 7b 20 7c 66 7c 20 66 2e 72 65 61 64 th) { |f| f.read
2390: 5f 62 79 74 65 20 7d 3b 20 22 72 65 61 64 20 6f _byte }; "read o
23a0: 6b 20 28 61 6c 6c 6f 77 65 64 3a 20 72 65 61 64 k (allowed: read
23b0: 2d 6f 6e 6c 79 29 22 20 7d 2c 0a 20 20 22 72 65 -only)" },. "re
23c0: 61 63 68 20 46 6f 73 73 69 6c 27 73 20 70 6f 72 ach Fossil's por
23d0: 74 22 20 20 20 20 20 20 20 20 20 20 20 20 20 3d t" =
23e0: 3e 20 2d 3e 20 7b 20 54 43 50 53 6f 63 6b 65 74 > -> { TCPSocket
23f0: 2e 6e 65 77 28 22 31 32 37 2e 30 2e 30 2e 31 22 .new("127.0.0.1"
2400: 2c 20 46 69 6c 65 2e 72 65 61 64 28 46 69 6c 65 , File.read(File
2410: 2e 6a 6f 69 6e 28 46 69 6c 65 2e 64 69 72 6e 61 .join(File.dirna
2420: 6d 65 28 73 6f 63 6b 65 74 29 2c 20 22 70 6f 72 me(socket), "por
2430: 74 22 29 29 2e 73 74 72 69 70 2e 74 6f 5f 69 2c t")).strip.to_i,
2440: 20 63 6f 6e 6e 65 63 74 5f 74 69 6d 65 6f 75 74 connect_timeout
2450: 3a 20 32 2e 73 65 63 6f 6e 64 73 29 2e 63 6c 6f : 2.seconds).clo
2460: 73 65 3b 20 22 43 4f 4e 4e 45 43 54 45 44 20 28 se; "CONNECTED (
2470: 62 61 64 29 22 20 7d 2c 0a 20 20 22 77 72 69 74 bad)" },. "writ
2480: 65 20 69 6e 20 69 74 73 20 73 6f 63 6b 65 74 20 e in its socket
2490: 64 69 72 65 63 74 6f 72 79 22 20 20 20 3d 3e 20 directory" =>
24a0: 2d 3e 20 7b 20 46 69 6c 65 2e 77 72 69 74 65 28 -> { File.write(
24b0: 46 69 6c 65 2e 6a 6f 69 6e 28 46 69 6c 65 2e 64 File.join(File.d
24c0: 69 72 6e 61 6d 65 28 73 6f 63 6b 65 74 29 2c 20 irname(socket),
24d0: 22 70 72 6f 62 65 22 29 2c 20 22 78 22 29 3b 20 "probe"), "x");
24e0: 22 77 72 69 74 74 65 6e 20 28 61 6c 6c 6f 77 65 "written (allowe
24f0: 64 3a 20 69 74 73 20 6f 6e 65 20 77 72 69 74 61 d: its one writa
2500: 62 6c 65 20 70 6c 61 63 65 29 22 20 7d 2c 0a 7d ble place)" },.}
2510: 0a 74 72 69 65 73 2e 65 61 63 68 20 64 6f 20 7c .tries.each do |
2520: 77 68 61 74 2c 20 74 72 79 7c 0a 20 20 6f 75 74 what, try|. out
2530: 63 6f 6d 65 20 3d 20 62 65 67 69 6e 0a 20 20 20 come = begin.
2540: 20 74 72 79 2e 63 61 6c 6c 0a 20 20 72 65 73 63 try.call. resc
2550: 75 65 20 65 0a 20 20 20 20 22 72 65 66 75 73 65 ue e. "refuse
2560: 64 20 28 23 7b 65 2e 63 6c 61 73 73 7d 3a 20 23 d (#{e.class}: #
2570: 7b 65 2e 6d 65 73 73 61 67 65 2e 74 72 79 20 26 {e.message.try &
2580: 2e 6c 69 6e 65 73 2e 66 69 72 73 74 7d 29 22 0a .lines.first})".
2590: 20 20 65 6e 64 0a 20 20 70 75 74 73 20 22 23 7b end. puts "#{
25a0: 77 68 61 74 7d 3a 20 23 7b 6f 75 74 63 6f 6d 65 what}: #{outcome
25b0: 7d 22 0a 65 6e 64 0a 00 00 00 00 00 00 00 00 00 }".end..........
25c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
25d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
25e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
25f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2600: 73 74 61 67 65 41 2d 72 65 63 6f 72 64 2f 73 74 stageA-record/st
2610: 61 67 65 41 2d 64 65 6d 6f 2e 73 68 00 00 00 00 ageA-demo.sh....
2620: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2630: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2640: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2650: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2660: 00 00 00 00 30 30 30 30 37 35 35 00 30 30 30 30 ....0000755.0000
2670: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
2680: 30 30 32 34 34 31 31 00 31 35 32 37 30 34 37 36 0024411.15270476
2690: 32 30 35 00 30 31 34 37 33 33 00 20 30 00 00 00 205.014733. 0...
26a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
26b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
26c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
26d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
26e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
26f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2700: 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
2710: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2720: 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
2730: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2740: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2750: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2760: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2770: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
27a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
27b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
27c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
27d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
27e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
27f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2800: 23 21 2f 62 69 6e 2f 62 61 73 68 0a 23 20 53 74 #!/bin/bash.# St
2810: 61 67 65 20 41 20 6f 6e 20 61 20 73 63 72 61 74 age A on a scrat
2820: 63 68 20 64 65 70 6c 6f 79 6d 65 6e 74 3a 20 74 ch deployment: t
2830: 68 65 20 72 65 63 65 69 70 74 20 73 65 72 76 69 he receipt servi
2840: 63 65 2c 20 74 68 65 20 6c 61 75 6e 63 68 65 72 ce, the launcher
2850: 27 73 20 43 47 49 0a 23 20 72 6f 75 74 65 20 61 's CGI.# route a
2860: 6e 64 20 74 68 65 20 63 6f 6e 66 69 6e 65 64 20 nd the confined
2870: 64 61 65 6d 6f 6e 2c 20 77 69 74 68 20 73 74 6f daemon, with sto
2880: 63 6b 20 46 6f 73 73 69 6c 20 32 2e 32 37 2e 20 ck Fossil 2.27.
2890: 55 73 61 67 65 3a 0a 23 20 20 20 73 74 61 67 65 Usage:.# stage
28a0: 41 2d 64 65 6d 6f 2e 73 68 20 54 52 45 45 20 4f A-demo.sh TREE O
28b0: 55 54 0a 23 20 54 52 45 45 20 69 73 20 74 68 65 UT.# TREE is the
28c0: 20 63 68 65 63 6b 6f 75 74 20 77 68 6f 73 65 20 checkout whose
28d0: 62 69 6e 2f 20 68 6f 6c 64 73 20 73 74 61 72 74 bin/ holds start
28e0: 2d 6f 63 78 2c 20 72 65 63 65 69 70 74 73 20 61 -ocx, receipts a
28f0: 6e 64 20 6f 63 78 32 3b 20 4f 55 54 0a 23 20 69 nd ocx2; OUT.# i
2900: 73 20 61 20 6e 65 77 20 64 69 72 65 63 74 6f 72 s a new director
2910: 79 20 66 6f 72 20 74 68 65 20 73 63 72 61 74 63 y for the scratc
2920: 68 20 64 65 70 6c 6f 79 6d 65 6e 74 20 61 6e 64 h deployment and
2930: 20 69 74 73 20 72 65 63 6f 72 64 2e 20 45 76 65 its record. Eve
2940: 72 79 0a 23 20 70 72 6f 63 65 73 73 20 69 74 20 ry.# process it
2950: 73 74 61 72 74 73 20 69 73 20 74 69 6d 65 2d 6c starts is time-l
2960: 69 6d 69 74 65 64 2c 20 61 6e 64 20 69 74 20 73 imited, and it s
2970: 74 6f 70 73 20 74 68 65 6d 20 61 6c 6c 20 61 74 tops them all at
2980: 20 74 68 65 20 65 6e 64 2e 0a 73 65 74 20 2d 75 the end..set -u
2990: 0a 54 52 45 45 3d 24 31 3b 20 4f 55 54 3d 24 32 .TREE=$1; OUT=$2
29a0: 0a 5b 20 2d 65 20 22 24 4f 55 54 22 20 5d 20 26 .[ -e "$OUT" ] &
29b0: 26 20 7b 20 65 63 68 6f 20 22 24 4f 55 54 20 65 & { echo "$OUT e
29c0: 78 69 73 74 73 22 3b 20 65 78 69 74 20 32 3b 20 xists"; exit 2;
29d0: 7d 0a 6d 6b 64 69 72 20 2d 70 20 22 24 4f 55 54 }.mkdir -p "$OUT
29e0: 22 3b 20 4f 55 54 3d 24 28 63 64 20 22 24 4f 55 "; OUT=$(cd "$OU
29f0: 54 22 20 26 26 20 70 77 64 29 0a 23 20 61 20 73 T" && pwd).# a s
2a00: 68 6f 72 74 20 70 61 74 68 3a 20 61 20 55 6e 69 hort path: a Uni
2a10: 78 20 73 6f 63 6b 65 74 27 73 20 70 61 74 68 20 x socket's path
2a20: 6d 61 79 20 62 65 20 61 74 20 6d 6f 73 74 20 31 may be at most 1
2a30: 30 37 20 62 79 74 65 73 0a 44 3d 2f 74 6d 70 2f 07 bytes.D=/tmp/
2a40: 73 41 2d 24 24 3b 20 4c 4f 47 3d 24 4f 55 54 2f sA-$$; LOG=$OUT/
2a50: 72 65 63 6f 72 64 2e 74 78 74 3b 20 72 6d 20 2d record.txt; rm -
2a60: 72 66 20 24 44 0a 6d 6b 64 69 72 20 2d 70 20 24 rf $D.mkdir -p $
2a70: 44 2f 66 6f 73 73 69 6c 20 24 44 2f 72 75 6e 20 D/fossil $D/run
2a80: 24 44 2f 72 65 6c 65 61 73 65 20 24 44 2f 64 61 $D/release $D/da
2a90: 65 6d 6f 6e 2f 6e 6f 64 65 20 24 44 2f 68 6f 6d emon/node $D/hom
2aa0: 65 2f 2e 63 6f 64 65 78 20 24 44 2f 65 78 74 0a e/.codex $D/ext.
2ab0: 65 78 65 63 20 3e 20 3e 28 74 65 65 20 2d 61 20 exec > >(tee -a
2ac0: 24 4c 4f 47 29 20 32 3e 26 31 0a 73 61 79 28 29 $LOG) 2>&1.say()
2ad0: 20 7b 20 65 63 68 6f 3b 20 65 63 68 6f 20 22 3d { echo; echo "=
2ae0: 3d 20 24 2a 22 3b 20 7d 0a 70 69 64 73 3d 28 29 = $*"; }.pids=()
2af0: 0a 63 6c 65 61 6e 75 70 28 29 20 7b 20 66 6f 72 .cleanup() { for
2b00: 20 70 20 69 6e 20 22 24 7b 70 69 64 73 5b 40 5d p in "${pids[@]
2b10: 7d 22 3b 20 64 6f 20 6b 69 6c 6c 20 24 70 20 32 }"; do kill $p 2
2b20: 3e 2f 64 65 76 2f 6e 75 6c 6c 3b 20 64 6f 6e 65 >/dev/null; done
2b30: 3b 20 77 61 69 74 20 32 3e 2f 64 65 76 2f 6e 75 ; wait 2>/dev/nu
2b40: 6c 6c 3b 20 7d 0a 74 72 61 70 20 27 63 6c 65 61 ll; }.trap 'clea
2b50: 6e 75 70 3b 20 72 6d 20 2d 72 66 20 24 44 27 20 nup; rm -rf $D'
2b60: 45 58 49 54 0a 0a 73 61 79 20 22 62 75 69 6c 64 EXIT..say "build
2b70: 3a 20 73 74 61 72 74 2d 6f 63 78 2c 20 72 65 63 : start-ocx, rec
2b80: 65 69 70 74 73 20 61 6e 64 20 6f 63 78 32 20 66 eipts and ocx2 f
2b90: 72 6f 6d 20 24 54 52 45 45 22 0a 42 49 4e 3d 24 rom $TREE".BIN=$
2ba0: 4f 55 54 2f 62 69 6e 3b 20 6d 6b 64 69 72 20 2d OUT/bin; mkdir -
2bb0: 70 20 24 42 49 4e 0a 66 6f 72 20 74 20 69 6e 20 p $BIN.for t in
2bc0: 73 74 61 72 74 2d 6f 63 78 20 72 65 63 65 69 70 start-ocx receip
2bd0: 74 73 3b 20 64 6f 20 6e 69 63 65 20 2d 6e 20 31 ts; do nice -n 1
2be0: 39 20 63 72 79 73 74 61 6c 20 62 75 69 6c 64 20 9 crystal build
2bf0: 2d 2d 72 65 6c 65 61 73 65 20 2d 6f 20 24 42 49 --release -o $BI
2c00: 4e 2f 24 74 20 24 54 52 45 45 2f 73 63 72 69 70 N/$t $TREE/scrip
2c10: 74 73 2f 24 74 2e 63 72 20 7c 7c 20 65 78 69 74 ts/$t.cr || exit
2c20: 20 31 3b 20 64 6f 6e 65 0a 63 70 20 24 54 52 45 1; done.cp $TRE
2c30: 45 2f 62 69 6e 2f 6f 63 78 32 20 24 42 49 4e 2f E/bin/ocx2 $BIN/
2c40: 6f 63 78 32 20 7c 7c 20 65 78 69 74 20 31 0a 52 ocx2 || exit 1.R
2c50: 45 4c 3d 64 65 6d 6f 30 30 30 30 30 30 30 31 0a EL=demo00000001.
2c60: 66 6f 72 20 72 20 69 6e 20 24 44 2f 72 65 6c 65 for r in $D/rele
2c70: 61 73 65 20 24 44 2f 64 61 65 6d 6f 6e 3b 20 64 ase $D/daemon; d
2c80: 6f 20 6d 6b 64 69 72 20 2d 70 20 24 72 2f 24 52 o mkdir -p $r/$R
2c90: 45 4c 20 24 72 2f 73 74 61 67 65 64 3b 20 63 70 EL $r/staged; cp
2ca0: 20 24 42 49 4e 2f 6f 63 78 32 20 24 72 2f 24 52 $BIN/ocx2 $r/$R
2cb0: 45 4c 2f 6f 63 78 32 3b 20 6c 6e 20 2d 73 20 24 EL/ocx2; ln -s $
2cc0: 52 45 4c 20 24 72 2f 63 75 72 72 65 6e 74 3b 20 REL $r/current;
2cd0: 64 6f 6e 65 0a 0a 73 61 79 20 22 73 65 72 76 65 done..say "serve
2ce0: 64 20 72 65 70 6f 73 69 74 6f 72 79 3a 20 64 65 d repository: de
2cf0: 6d 6f 2e 66 6f 73 73 69 6c 2c 20 75 73 65 72 73 mo.fossil, users
2d00: 2c 20 63 68 61 74 20 74 69 6d 65 6c 69 6e 65 22 , chat timeline"
2d10: 0a 46 3d 2f 75 73 72 2f 62 69 6e 2f 66 6f 73 73 .F=/usr/bin/foss
2d20: 69 6c 3b 20 52 3d 24 44 2f 66 6f 73 73 69 6c 2f il; R=$D/fossil/
2d30: 64 65 6d 6f 2e 66 6f 73 73 69 6c 0a 65 78 70 6f demo.fossil.expo
2d40: 72 74 20 48 4f 4d 45 3d 24 4f 55 54 2f 61 64 6d rt HOME=$OUT/adm
2d50: 69 6e 68 6f 6d 65 3b 20 6d 6b 64 69 72 20 2d 70 inhome; mkdir -p
2d60: 20 24 48 4f 4d 45 0a 24 46 20 6e 65 77 20 24 52 $HOME.$F new $R
2d70: 20 2d 2d 61 64 6d 69 6e 2d 75 73 65 72 20 62 6f --admin-user bo
2d80: 73 73 20 3e 2f 64 65 76 2f 6e 75 6c 6c 0a 24 46 ss >/dev/null.$F
2d90: 20 75 73 65 72 20 70 61 73 73 77 6f 72 64 20 62 user password b
2da0: 6f 73 73 20 62 6f 73 73 2d 70 77 20 2d 52 20 24 oss boss-pw -R $
2db0: 52 0a 66 6f 72 20 75 20 69 6e 20 22 64 65 6d 6f R.for u in "demo
2dc0: 2d 6e 6f 64 65 20 67 6f 43 34 77 20 6e 6f 64 65 -node goC4w node
2dd0: 2d 70 77 22 20 22 62 75 69 6c 64 65 72 20 67 69 -pw" "builder gi
2de0: 6f 32 34 20 62 75 69 6c 64 65 72 2d 70 77 22 20 o24 builder-pw"
2df0: 22 76 69 65 77 65 72 20 6f 32 20 76 69 65 77 65 "viewer o2 viewe
2e00: 72 2d 70 77 22 3b 20 64 6f 20 73 65 74 20 2d 2d r-pw"; do set --
2e10: 20 24 75 0a 20 20 24 46 20 75 73 65 72 20 6e 65 $u. $F user ne
2e20: 77 20 24 31 20 24 31 40 78 20 24 33 20 2d 52 20 w $1 $1@x $3 -R
2e30: 24 52 20 3e 2f 64 65 76 2f 6e 75 6c 6c 3b 20 24 $R >/dev/null; $
2e40: 46 20 75 73 65 72 20 63 61 70 61 62 69 6c 69 74 F user capabilit
2e50: 69 65 73 20 24 31 20 24 32 20 2d 52 20 24 52 20 ies $1 $2 -R $R
2e60: 3e 2f 64 65 76 2f 6e 75 6c 6c 3b 20 64 6f 6e 65 >/dev/null; done
2e70: 0a 24 46 20 73 65 74 74 69 6e 67 73 20 63 68 61 .$F settings cha
2e80: 74 2d 74 69 6d 65 6c 69 6e 65 2d 75 73 65 72 20 t-timeline-user
2e90: 6f 63 78 2d 74 69 6d 65 6c 69 6e 65 20 2d 52 20 ocx-timeline -R
2ea0: 24 52 0a 24 46 20 73 65 74 74 69 6e 67 73 20 63 $R.$F settings c
2eb0: 68 61 74 2d 70 6f 6c 6c 2d 74 69 6d 65 6f 75 74 hat-poll-timeout
2ec0: 20 33 20 2d 52 20 24 52 0a 63 68 6d 6f 64 20 36 3 -R $R.chmod 6
2ed0: 30 30 20 24 52 3b 20 6c 73 20 2d 6c 20 24 52 0a 00 $R; ls -l $R.
2ee0: 0a 73 61 79 20 22 72 65 63 65 69 70 74 20 73 65 .say "receipt se
2ef0: 72 76 69 63 65 2c 20 74 68 72 6f 75 67 68 20 74 rvice, through t
2f00: 68 65 20 6c 61 75 6e 63 68 65 72 27 73 20 72 65 he launcher's re
2f10: 63 65 69 70 74 73 20 70 6f 6c 69 63 79 22 0a 74 ceipts policy".t
2f20: 69 6d 65 6f 75 74 20 39 30 30 20 24 42 49 4e 2f imeout 900 $BIN/
2f30: 73 74 61 72 74 2d 6f 63 78 20 2d 2d 73 63 72 61 start-ocx --scra
2f40: 74 63 68 20 24 44 20 72 65 63 65 69 70 74 73 20 tch $D receipts
2f50: 32 3e 24 4f 55 54 2f 72 65 63 65 69 70 74 73 2e 2>$OUT/receipts.
2f60: 65 72 72 20 26 20 70 69 64 73 2b 3d 28 24 21 29 err & pids+=($!)
2f70: 0a 73 6c 65 65 70 20 31 3b 20 6c 73 20 2d 6c 20 .sleep 1; ls -l
2f80: 24 44 2f 72 75 6e 2f 0a 0a 73 61 79 20 22 46 6f $D/run/..say "Fo
2f90: 73 73 69 6c 20 73 65 72 76 65 72 2c 20 69 74 73 ssil server, its
2fa0: 20 65 78 74 72 6f 6f 74 27 73 20 6f 63 78 32 2d extroot's ocx2-
2fb0: 63 67 69 20 74 68 65 20 6c 61 75 6e 63 68 65 72 cgi the launcher
2fc0: 22 0a 70 72 69 6e 74 66 20 27 23 21 2f 62 69 6e ".printf '#!/bin
2fd0: 2f 62 61 73 68 5c 6e 65 78 65 63 20 2d 61 20 6f /bash\nexec -a o
2fe0: 63 78 32 2d 63 67 69 20 25 73 20 2d 2d 73 63 72 cx2-cgi %s --scr
2ff0: 61 74 63 68 20 25 73 5c 6e 27 20 24 42 49 4e 2f atch %s\n' $BIN/
3000: 73 74 61 72 74 2d 6f 63 78 20 24 44 20 3e 20 24 start-ocx $D > $
3010: 44 2f 65 78 74 2f 6f 63 78 32 2d 63 67 69 3b 20 D/ext/ocx2-cgi;
3020: 63 68 6d 6f 64 20 37 35 35 20 24 44 2f 65 78 74 chmod 755 $D/ext
3030: 2f 6f 63 78 32 2d 63 67 69 0a 50 3d 24 28 70 79 /ocx2-cgi.P=$(py
3040: 74 68 6f 6e 33 20 2d 63 20 27 69 6d 70 6f 72 74 thon3 -c 'import
3050: 20 73 6f 63 6b 65 74 3b 73 3d 73 6f 63 6b 65 74 socket;s=socket
3060: 2e 73 6f 63 6b 65 74 28 29 3b 73 2e 62 69 6e 64 .socket();s.bind
3070: 28 28 22 31 32 37 2e 30 2e 30 2e 31 22 2c 30 29 (("127.0.0.1",0)
3080: 29 3b 70 72 69 6e 74 28 73 2e 67 65 74 73 6f 63 );print(s.getsoc
3090: 6b 6e 61 6d 65 28 29 5b 31 5d 29 27 29 0a 55 3d kname()[1])').U=
30a0: 68 74 74 70 3a 2f 2f 31 32 37 2e 30 2e 30 2e 31 http://127.0.0.1
30b0: 3a 24 50 2f 64 65 6d 6f 0a 74 69 6d 65 6f 75 74 :$P/demo.timeout
30c0: 20 39 30 30 20 24 46 20 73 65 72 76 65 72 20 2d 900 $F server -
30d0: 2d 70 6f 72 74 20 24 50 20 2d 2d 6c 6f 63 61 6c -port $P --local
30e0: 68 6f 73 74 20 2d 2d 6e 6f 6a 61 69 6c 20 2d 2d host --nojail --
30f0: 72 65 70 6f 6c 69 73 74 20 24 44 2f 66 6f 73 73 repolist $D/foss
3100: 69 6c 20 2d 2d 65 78 74 72 6f 6f 74 20 24 44 2f il --extroot $D/
3110: 65 78 74 20 3e 24 4f 55 54 2f 66 6f 73 73 69 6c ext >$OUT/fossil
3120: 2e 6c 6f 67 20 32 3e 26 31 20 26 20 70 69 64 73 .log 2>&1 & pids
3130: 2b 3d 28 24 21 29 0a 66 6f 72 20 69 20 69 6e 20 +=($!).for i in
3140: 24 28 73 65 71 20 35 30 29 3b 20 64 6f 20 63 75 $(seq 50); do cu
3150: 72 6c 20 2d 73 20 2d 6f 20 2f 64 65 76 2f 6e 75 rl -s -o /dev/nu
3160: 6c 6c 20 68 74 74 70 3a 2f 2f 31 32 37 2e 30 2e ll http://127.0.
3170: 30 2e 31 3a 24 50 2f 20 26 26 20 62 72 65 61 6b 0.1:$P/ && break
3180: 3b 20 73 6c 65 65 70 20 30 2e 32 3b 20 64 6f 6e ; sleep 0.2; don
3190: 65 0a 0a 73 61 79 20 22 74 68 65 20 64 61 65 6d e..say "the daem
31a0: 6f 6e 27 73 20 6e 6f 64 65 3a 20 6e 6f 64 65 73 on's node: nodes
31b0: 2e 6a 73 6f 6e 20 61 6e 64 20 63 72 65 64 65 6e .json and creden
31c0: 74 69 61 6c 73 22 0a 6d 6b 64 69 72 20 2d 70 20 tials".mkdir -p
31d0: 24 44 2f 64 61 65 6d 6f 6e 2f 6e 6f 64 65 2f 63 $D/daemon/node/c
31e0: 72 65 64 65 6e 74 69 61 6c 73 20 24 44 2f 64 61 redentials $D/da
31f0: 65 6d 6f 6e 2f 6e 6f 64 65 2f 63 6c 6f 6e 65 73 emon/node/clones
3200: 3b 20 63 68 6d 6f 64 20 37 30 30 20 24 44 2f 64 ; chmod 700 $D/d
3210: 61 65 6d 6f 6e 2f 6e 6f 64 65 0a 70 72 69 6e 74 aemon/node.print
3220: 66 20 27 7b 22 75 73 65 72 22 3a 22 64 65 6d 6f f '{"user":"demo
3230: 2d 6e 6f 64 65 22 2c 22 70 61 73 73 77 6f 72 64 -node","password
3240: 22 3a 22 6e 6f 64 65 2d 70 77 22 2c 22 72 75 6e ":"node-pw","run
3250: 73 22 3a 7b 22 62 75 69 6c 64 65 72 22 3a 22 62 s":{"builder":"b
3260: 75 69 6c 64 65 72 2d 70 77 22 7d 7d 27 20 3e 20 uilder-pw"}}' >
3270: 24 44 2f 64 61 65 6d 6f 6e 2f 6e 6f 64 65 2f 63 $D/daemon/node/c
3280: 72 65 64 65 6e 74 69 61 6c 73 2f 64 65 6d 6f 2e redentials/demo.
3290: 6a 73 6f 6e 3b 20 63 68 6d 6f 64 20 36 30 30 20 json; chmod 600
32a0: 24 44 2f 64 61 65 6d 6f 6e 2f 6e 6f 64 65 2f 63 $D/daemon/node/c
32b0: 72 65 64 65 6e 74 69 61 6c 73 2f 64 65 6d 6f 2e redentials/demo.
32c0: 6a 73 6f 6e 0a 70 72 69 6e 74 66 20 27 5b 7b 22 json.printf '[{"
32d0: 63 6c 6f 6e 65 22 3a 22 25 73 22 2c 22 73 65 72 clone":"%s","ser
32e0: 76 65 72 22 3a 22 25 73 22 2c 22 63 72 65 64 65 ver":"%s","crede
32f0: 6e 74 69 61 6c 73 22 3a 22 25 73 22 7d 5d 27 20 ntials":"%s"}]'
3300: 24 44 2f 64 61 65 6d 6f 6e 2f 6e 6f 64 65 2f 63 $D/daemon/node/c
3310: 6c 6f 6e 65 73 2f 64 65 6d 6f 2e 66 6f 73 73 69 lones/demo.fossi
3320: 6c 20 24 55 20 24 44 2f 64 61 65 6d 6f 6e 2f 6e l $U $D/daemon/n
3330: 6f 64 65 2f 63 72 65 64 65 6e 74 69 61 6c 73 2f ode/credentials/
3340: 64 65 6d 6f 2e 6a 73 6f 6e 20 3e 20 24 44 2f 64 demo.json > $D/d
3350: 61 65 6d 6f 6e 2f 6e 6f 64 65 2f 6e 6f 64 65 73 aemon/node/nodes
3360: 2e 6a 73 6f 6e 3b 20 63 68 6d 6f 64 20 36 30 30 .json; chmod 600
3370: 20 24 44 2f 64 61 65 6d 6f 6e 2f 6e 6f 64 65 2f $D/daemon/node/
3380: 6e 6f 64 65 73 2e 6a 73 6f 6e 0a 0a 73 61 79 20 nodes.json..say
3390: 22 63 6f 6e 66 69 6e 65 64 20 64 61 65 6d 6f 6e "confined daemon
33a0: 2c 20 74 68 72 6f 75 67 68 20 74 68 65 20 6c 61 , through the la
33b0: 75 6e 63 68 65 72 27 73 20 64 61 65 6d 6f 6e 20 uncher's daemon
33c0: 70 6f 6c 69 63 79 22 0a 74 69 6d 65 6f 75 74 20 policy".timeout
33d0: 39 30 30 20 24 42 49 4e 2f 73 74 61 72 74 2d 6f 900 $BIN/start-o
33e0: 63 78 20 2d 2d 73 63 72 61 74 63 68 20 24 44 20 cx --scratch $D
33f0: 64 61 65 6d 6f 6e 20 3e 20 24 4f 55 54 2f 64 61 daemon > $OUT/da
3400: 65 6d 6f 6e 2e 6c 6f 67 20 32 3e 26 31 20 26 20 emon.log 2>&1 &
3410: 70 69 64 73 2b 3d 28 24 21 29 0a 66 6f 72 20 69 pids+=($!).for i
3420: 20 69 6e 20 24 28 73 65 71 20 36 30 29 3b 20 64 in $(seq 60); d
3430: 6f 20 5b 20 2d 65 20 24 44 2f 64 61 65 6d 6f 6e o [ -e $D/daemon
3440: 2f 6e 6f 64 65 2f 63 6c 6f 6e 65 73 2f 64 65 6d /node/clones/dem
3450: 6f 2e 66 6f 73 73 69 6c 20 5d 20 26 26 20 67 72 o.fossil ] && gr
3460: 65 70 20 2d 71 20 72 6f 75 6e 64 20 24 44 2f 64 ep -q round $D/d
3470: 61 65 6d 6f 6e 2f 6e 6f 64 65 2f 64 61 65 6d 6f aemon/node/daemo
3480: 6e 2e 6c 6f 67 20 32 3e 2f 64 65 76 2f 6e 75 6c n.log 2>/dev/nul
3490: 6c 20 26 26 20 62 72 65 61 6b 3b 20 73 6c 65 65 l && break; slee
34a0: 70 20 31 3b 20 64 6f 6e 65 0a 74 61 69 6c 20 2d p 1; done.tail -
34b0: 33 20 24 44 2f 64 61 65 6d 6f 6e 2f 6e 6f 64 65 3 $D/daemon/node
34c0: 2f 64 61 65 6d 6f 6e 2e 6c 6f 67 20 32 3e 2f 64 /daemon.log 2>/d
34d0: 65 76 2f 6e 75 6c 6c 3b 20 74 61 69 6c 20 2d 35 ev/null; tail -5
34e0: 20 24 4f 55 54 2f 64 61 65 6d 6f 6e 2e 6c 6f 67 $OUT/daemon.log
34f0: 0a 0a 23 20 41 20 70 72 6f 62 65 20 61 20 72 75 ..# A probe a ru
3500: 6e 27 73 20 70 72 6f 63 65 73 73 20 72 75 6e 73 n's process runs
3510: 3a 20 77 68 61 74 20 69 74 20 63 61 6e 20 73 65 : what it can se
3520: 65 20 6f 66 20 74 68 65 20 73 65 72 76 65 64 20 e of the served
3530: 72 65 70 6f 73 69 74 6f 72 69 65 73 2e 0a 50 52 repositories..PR
3540: 4f 42 45 3d 22 65 63 68 6f 20 75 69 64 3d 5c 24 OBE="echo uid=\$
3550: 28 69 64 20 2d 75 29 3b 20 66 6f 72 20 70 20 69 (id -u); for p i
3560: 6e 20 24 44 2f 66 6f 73 73 69 6c 20 24 52 3b 20 n $D/fossil $R;
3570: 64 6f 20 5b 20 2d 65 20 5c 24 70 20 5d 20 26 26 do [ -e \$p ] &&
3580: 20 65 63 68 6f 20 56 49 53 49 42 4c 45 20 5c 24 echo VISIBLE \$
3590: 70 20 7c 7c 20 65 63 68 6f 20 61 62 73 65 6e 74 p || echo absent
35a0: 20 5c 24 70 3b 20 64 6f 6e 65 3b 20 68 65 61 64 \$p; done; head
35b0: 20 2d 63 20 31 36 20 24 52 20 3e 2f 64 65 76 2f -c 16 $R >/dev/
35c0: 6e 75 6c 6c 20 32 3e 26 31 20 26 26 20 65 63 68 null 2>&1 && ech
35d0: 6f 20 52 45 41 44 2d 4f 4b 20 7c 7c 20 65 63 68 o READ-OK || ech
35e0: 6f 20 72 65 61 64 2d 72 65 66 75 73 65 64 3b 20 o read-refused;
35f0: 6e 3d 30 3b 20 66 6f 72 20 78 20 69 6e 20 2f 70 n=0; for x in /p
3600: 72 6f 63 2f 5b 30 2d 39 5d 2a 2f 72 6f 6f 74 24 roc/[0-9]*/root$
3610: 52 3b 20 64 6f 20 5b 20 2d 72 20 5c 24 78 20 5d R; do [ -r \$x ]
3620: 20 26 26 20 6e 3d 5c 24 28 28 6e 2b 31 29 29 3b && n=\$((n+1));
3630: 20 64 6f 6e 65 3b 20 65 63 68 6f 20 70 72 6f 63 done; echo proc
3640: 2d 70 61 74 68 73 2d 72 65 61 64 61 62 6c 65 3d -paths-readable=
3650: 5c 24 6e 22 0a 70 6f 73 74 5f 72 75 6e 28 29 20 \$n".post_run()
3660: 7b 20 23 20 24 31 20 74 69 74 6c 65 2c 20 24 32 { # $1 title, $2
3670: 20 72 75 6e 20 4a 53 4f 4e 3a 20 70 6f 73 74 65 run JSON: poste
3680: 64 20 62 79 20 62 6f 73 73 20 74 68 72 6f 75 67 d by boss throug
3690: 68 20 46 6f 73 73 69 6c 27 73 20 6f 77 6e 20 66 h Fossil's own f
36a0: 6f 72 6d 0a 20 20 70 79 74 68 6f 6e 33 20 2d 20 orm. python3 -
36b0: 22 24 55 22 20 22 24 31 22 20 22 24 32 22 20 3c "$U" "$1" "$2" <
36c0: 3c 27 45 27 0a 69 6d 70 6f 72 74 20 68 74 74 70 <'E'.import http
36d0: 2e 63 6f 6f 6b 69 65 6a 61 72 2c 20 72 65 2c 20 .cookiejar, re,
36e0: 73 79 73 2c 20 75 72 6c 6c 69 62 2e 70 61 72 73 sys, urllib.pars
36f0: 65 2c 20 75 72 6c 6c 69 62 2e 72 65 71 75 65 73 e, urllib.reques
3700: 74 0a 62 61 73 65 2c 20 74 69 74 6c 65 2c 20 72 t.base, title, r
3710: 75 6e 20 3d 20 73 79 73 2e 61 72 67 76 5b 31 3a un = sys.argv[1:
3720: 34 5d 0a 6a 61 72 20 3d 20 68 74 74 70 2e 63 6f 4].jar = http.co
3730: 6f 6b 69 65 6a 61 72 2e 43 6f 6f 6b 69 65 4a 61 okiejar.CookieJa
3740: 72 28 29 3b 20 6f 70 20 3d 20 75 72 6c 6c 69 62 r(); op = urllib
3750: 2e 72 65 71 75 65 73 74 2e 62 75 69 6c 64 5f 6f .request.build_o
3760: 70 65 6e 65 72 28 75 72 6c 6c 69 62 2e 72 65 71 pener(urllib.req
3770: 75 65 73 74 2e 48 54 54 50 43 6f 6f 6b 69 65 50 uest.HTTPCookieP
3780: 72 6f 63 65 73 73 6f 72 28 6a 61 72 29 29 0a 6f rocessor(jar)).o
3790: 70 2e 6f 70 65 6e 28 62 61 73 65 20 2b 20 22 2f p.open(base + "/
37a0: 6c 6f 67 69 6e 22 2c 20 75 72 6c 6c 69 62 2e 70 login", urllib.p
37b0: 61 72 73 65 2e 75 72 6c 65 6e 63 6f 64 65 28 7b arse.urlencode({
37c0: 22 75 22 3a 20 22 62 6f 73 73 22 2c 20 22 70 22 "u": "boss", "p"
37d0: 3a 20 22 62 6f 73 73 2d 70 77 22 2c 20 22 69 6e : "boss-pw", "in
37e0: 22 3a 20 22 31 22 7d 29 2e 65 6e 63 6f 64 65 28 ": "1"}).encode(
37f0: 29 29 0a 63 73 72 66 20 3d 20 72 65 2e 73 65 61 )).csrf = re.sea
3800: 72 63 68 28 72 27 6e 61 6d 65 3d 22 63 73 72 66 rch(r'name="csrf
3810: 22 20 76 61 6c 75 65 3d 22 28 5b 5e 22 5d 2b 29 " value="([^"]+)
3820: 22 27 2c 20 6f 70 2e 6f 70 65 6e 28 62 61 73 65 "', op.open(base
3830: 20 2b 20 22 2f 66 6f 72 75 6d 6e 65 77 22 29 2e + "/forumnew").
3840: 72 65 61 64 28 29 2e 64 65 63 6f 64 65 28 29 29 read().decode())
3850: 2e 67 72 6f 75 70 28 31 29 0a 72 65 71 20 3d 20 .group(1).req =
3860: 75 72 6c 6c 69 62 2e 72 65 71 75 65 73 74 2e 52 urllib.request.R
3870: 65 71 75 65 73 74 28 62 61 73 65 20 2b 20 22 2f equest(base + "/
3880: 66 6f 72 75 6d 65 31 22 2c 20 75 72 6c 6c 69 62 forume1", urllib
3890: 2e 70 61 72 73 65 2e 75 72 6c 65 6e 63 6f 64 65 .parse.urlencode
38a0: 28 7b 22 63 73 72 66 22 3a 20 63 73 72 66 2c 20 ({"csrf": csrf,
38b0: 22 74 69 74 6c 65 22 3a 20 74 69 74 6c 65 2c 20 "title": title,
38c0: 22 6d 69 6d 65 74 79 70 65 22 3a 20 22 74 65 78 "mimetype": "tex
38d0: 74 2f 78 2d 6d 61 72 6b 64 6f 77 6e 22 2c 20 22 t/x-markdown", "
38e0: 63 6f 6e 74 65 6e 74 22 3a 20 22 60 60 60 6a 73 content": "```js
38f0: 6f 6e 5c 6e 22 20 2b 20 72 75 6e 20 2b 20 22 5c on\n" + run + "\
3900: 6e 60 60 60 5c 6e 22 2c 20 22 73 75 62 6d 69 74 n```\n", "submit
3910: 22 3a 20 22 53 75 62 6d 69 74 22 7d 29 2e 65 6e ": "Submit"}).en
3920: 63 6f 64 65 28 29 29 0a 72 65 71 2e 61 64 64 5f code()).req.add_
3930: 68 65 61 64 65 72 28 22 52 65 66 65 72 65 72 22 header("Referer"
3940: 2c 20 62 61 73 65 20 2b 20 22 2f 66 6f 72 75 6d , base + "/forum
3950: 6e 65 77 22 29 0a 70 72 69 6e 74 28 6f 70 2e 6f new").print(op.o
3960: 70 65 6e 28 72 65 71 29 2e 67 65 74 75 72 6c 28 pen(req).geturl(
3970: 29 2e 72 73 70 6c 69 74 28 22 2f 22 2c 20 31 29 ).rsplit("/", 1)
3980: 5b 2d 31 5d 29 0a 45 0a 7d 0a 4a 50 52 4f 42 45 [-1]).E.}.JPROBE
3990: 3d 24 28 70 79 74 68 6f 6e 33 20 2d 63 20 27 69 =$(python3 -c 'i
39a0: 6d 70 6f 72 74 20 6a 73 6f 6e 2c 73 79 73 3b 20 mport json,sys;
39b0: 70 72 69 6e 74 28 6a 73 6f 6e 2e 64 75 6d 70 73 print(json.dumps
39c0: 28 73 79 73 2e 61 72 67 76 5b 31 5d 29 29 27 20 (sys.argv[1]))'
39d0: 22 24 50 52 4f 42 45 22 29 0a 53 41 4e 44 42 4f "$PROBE").SANDBO
39e0: 58 45 44 3d 27 7b 22 6f 63 78 22 3a 20 31 2c 20 XED='{"ocx": 1,
39f0: 22 6b 69 6e 64 22 3a 20 22 72 75 6e 22 2c 20 22 "kind": "run", "
3a00: 6e 6f 64 65 22 3a 20 22 64 65 6d 6f 2d 6e 6f 64 node": "demo-nod
3a10: 65 22 2c 20 22 6f 62 6a 65 63 74 69 76 65 22 3a e", "objective":
3a20: 20 22 50 72 6f 62 65 20 66 72 6f 6d 20 61 6e 20 "Probe from an
3a30: 61 67 65 6e 74 20 73 61 6e 64 62 6f 78 2e 22 2c agent sandbox.",
3a40: 20 22 77 6f 72 6b 73 70 61 63 65 22 3a 20 5b 7b "workspace": [{
3a50: 22 73 74 65 70 22 3a 20 22 64 69 72 65 63 74 6f "step": "directo
3a60: 72 79 22 2c 20 22 61 74 22 3a 20 22 24 24 72 6f ry", "at": "$$ro
3a70: 6f 74 24 24 2f 24 24 75 73 65 72 24 24 2f 70 72 ot$$/$$user$$/pr
3a80: 6f 6a 65 63 74 73 2f 24 24 70 72 6f 6a 65 63 74 ojects/$$project
3a90: 24 24 2f 24 24 72 75 6e 24 24 22 7d 5d 2c 20 22 $$/$$run$$"}], "
3aa0: 73 61 6e 64 62 6f 78 22 3a 20 7b 22 75 69 64 22 sandbox": {"uid"
3ab0: 3a 20 31 30 30 30 2c 20 22 67 69 64 22 3a 20 31 : 1000, "gid": 1
3ac0: 30 30 30 2c 20 22 63 61 70 61 62 69 6c 69 74 69 000, "capabiliti
3ad0: 65 73 22 3a 20 5b 5d 2c 20 22 6e 65 74 77 6f 72 es": [], "networ
3ae0: 6b 22 3a 20 66 61 6c 73 65 2c 20 22 6f 77 6e 5f k": false, "own_
3af0: 73 65 73 73 69 6f 6e 22 3a 20 74 72 75 65 2c 20 session": true,
3b00: 22 65 6e 64 73 5f 77 69 74 68 5f 6e 6f 64 65 22 "ends_with_node"
3b10: 3a 20 74 72 75 65 2c 20 22 72 65 61 64 5f 6f 6e : true, "read_on
3b20: 6c 79 22 3a 20 5b 22 2f 75 73 72 22 2c 20 22 2f ly": ["/usr", "/
3b30: 62 69 6e 22 2c 20 22 2f 6c 69 62 22 2c 20 22 2f bin", "/lib", "/
3b40: 6c 69 62 36 34 22 5d 2c 20 22 72 65 61 64 5f 77 lib64"], "read_w
3b50: 72 69 74 65 22 3a 20 5b 22 24 24 77 6f 72 6b 73 rite": ["$$works
3b60: 70 61 63 65 24 24 22 5d 2c 20 22 68 6f 6d 65 73 pace$$"], "homes
3b70: 22 3a 20 5b 5d 2c 20 22 66 69 6c 65 73 22 3a 20 ": [], "files":
3b80: 5b 5d 2c 20 22 70 72 6f 63 22 3a 20 22 2f 70 72 [], "proc": "/pr
3b90: 6f 63 22 2c 20 22 64 65 76 22 3a 20 22 2f 64 65 oc", "dev": "/de
3ba0: 76 22 2c 20 22 74 6d 70 22 3a 20 22 2f 74 6d 70 v", "tmp": "/tmp
3bb0: 22 7d 2c 20 22 6c 69 6d 69 74 73 22 3a 20 7b 22 "}, "limits": {"
3bc0: 77 61 6c 6c 22 3a 20 22 32 6d 22 7d 2c 20 22 70 wall": "2m"}, "p
3bd0: 72 6f 63 65 73 73 22 3a 20 7b 22 75 73 65 72 22 rocess": {"user"
3be0: 3a 20 22 62 75 69 6c 64 65 72 22 2c 20 22 63 6f : "builder", "co
3bf0: 6d 6d 61 6e 64 22 3a 20 5b 22 2f 62 69 6e 2f 73 mmand": ["/bin/s
3c00: 68 22 2c 20 22 2d 63 22 2c 20 27 22 24 4a 50 52 h", "-c", '"$JPR
3c10: 4f 42 45 22 27 5d 2c 20 22 65 6e 76 22 3a 20 7b OBE"'], "env": {
3c20: 22 50 41 54 48 22 3a 20 22 2f 75 73 72 2f 62 69 "PATH": "/usr/bi
3c30: 6e 3a 2f 62 69 6e 22 7d 2c 20 22 6b 65 65 70 22 n:/bin"}, "keep"
3c40: 3a 20 7b 22 73 74 64 6f 75 74 5f 77 68 65 6e 22 : {"stdout_when"
3c50: 3a 20 22 61 6c 77 61 79 73 22 7d 7d 7d 27 0a 42 : "always"}}}'.B
3c60: 41 52 45 3d 27 7b 22 6f 63 78 22 3a 20 31 2c 20 ARE='{"ocx": 1,
3c70: 22 6b 69 6e 64 22 3a 20 22 72 75 6e 22 2c 20 22 "kind": "run", "
3c80: 6e 6f 64 65 22 3a 20 22 64 65 6d 6f 2d 6e 6f 64 node": "demo-nod
3c90: 65 22 2c 20 22 6f 62 6a 65 63 74 69 76 65 22 3a e", "objective":
3ca0: 20 22 50 72 6f 62 65 20 66 72 6f 6d 20 74 68 65 "Probe from the
3cb0: 20 64 61 65 6d 6f 6e 20 69 74 73 65 6c 66 2c 20 daemon itself,
3cc0: 75 6e 63 6f 6e 66 69 6e 65 64 20 62 79 20 61 6e unconfined by an
3cd0: 79 20 72 75 6e 20 73 61 6e 64 62 6f 78 2e 22 2c y run sandbox.",
3ce0: 20 22 70 72 6f 63 65 73 73 22 3a 20 7b 22 75 73 "process": {"us
3cf0: 65 72 22 3a 20 22 62 75 69 6c 64 65 72 22 2c 20 er": "builder",
3d00: 22 63 6f 6d 6d 61 6e 64 22 3a 20 5b 22 2f 62 69 "command": ["/bi
3d10: 6e 2f 73 68 22 2c 20 22 2d 63 22 2c 20 27 22 24 n/sh", "-c", '"$
3d20: 4a 50 52 4f 42 45 22 27 5d 2c 20 22 65 6e 76 22 JPROBE"'], "env"
3d30: 3a 20 7b 22 50 41 54 48 22 3a 20 22 2f 75 73 72 : {"PATH": "/usr
3d40: 2f 62 69 6e 3a 2f 62 69 6e 22 7d 2c 20 22 6b 65 /bin:/bin"}, "ke
3d50: 65 70 22 3a 20 7b 22 73 74 64 6f 75 74 5f 77 68 ep": {"stdout_wh
3d60: 65 6e 22 3a 20 22 61 6c 77 61 79 73 22 7d 7d 7d en": "always"}}}
3d70: 27 0a 0a 73 61 79 20 22 74 77 6f 20 72 75 6e 73 '..say "two runs
3d80: 2c 20 70 6f 73 74 65 64 20 62 79 20 62 6f 73 73 , posted by boss
3d90: 20 28 73 65 74 75 70 29 20 74 68 72 6f 75 67 68 (setup) through
3da0: 20 46 6f 73 73 69 6c 27 73 20 66 6f 72 6d 22 0a Fossil's form".
3db0: 52 55 4e 31 3d 24 28 70 6f 73 74 5f 72 75 6e 20 RUN1=$(post_run
3dc0: 22 73 61 6e 64 62 6f 78 65 64 20 70 72 6f 62 65 "sandboxed probe
3dd0: 22 20 22 24 53 41 4e 44 42 4f 58 45 44 22 29 3b " "$SANDBOXED");
3de0: 20 65 63 68 6f 20 22 73 61 6e 64 62 6f 78 65 64 echo "sandboxed
3df0: 20 72 75 6e 20 24 52 55 4e 31 22 0a 52 55 4e 32 run $RUN1".RUN2
3e00: 3d 24 28 70 6f 73 74 5f 72 75 6e 20 22 75 6e 63 =$(post_run "unc
3e10: 6f 6e 66 69 6e 65 64 20 70 72 6f 62 65 22 20 22 onfined probe" "
3e20: 24 42 41 52 45 22 29 3b 20 65 63 68 6f 20 22 75 $BARE"); echo "u
3e30: 6e 63 6f 6e 66 69 6e 65 64 20 72 75 6e 20 24 52 nconfined run $R
3e40: 55 4e 32 22 0a 66 6f 72 20 69 20 69 6e 20 24 28 UN2".for i in $(
3e50: 73 65 71 20 39 30 29 3b 20 64 6f 20 5b 20 22 24 seq 90); do [ "$
3e60: 28 24 46 20 73 71 6c 20 2d 52 20 24 52 20 22 53 ($F sql -R $R "S
3e70: 45 4c 45 43 54 20 63 6f 75 6e 74 28 2a 29 20 46 ELECT count(*) F
3e80: 52 4f 4d 20 66 6f 72 75 6d 70 6f 73 74 20 66 20 ROM forumpost f
3e90: 4a 4f 49 4e 20 62 6c 6f 62 20 62 20 4f 4e 20 62 JOIN blob b ON b
3ea0: 2e 72 69 64 3d 66 2e 66 70 69 64 20 57 48 45 52 .rid=f.fpid WHER
3eb0: 45 20 62 2e 63 6f 6e 74 65 6e 74 20 49 53 20 4e E b.content IS N
3ec0: 4f 54 20 4e 55 4c 4c 22 20 32 3e 2f 64 65 76 2f OT NULL" 2>/dev/
3ed0: 6e 75 6c 6c 29 22 20 2d 67 65 20 36 20 5d 20 26 null)" -ge 6 ] &
3ee0: 26 20 62 72 65 61 6b 3b 20 73 6c 65 65 70 20 31 & break; sleep 1
3ef0: 3b 20 64 6f 6e 65 0a 73 6c 65 65 70 20 33 0a 73 ; done.sleep 3.s
3f00: 61 79 20 22 77 68 61 74 20 74 68 65 20 72 75 6e ay "what the run
3f10: 73 20 70 6f 73 74 65 64 20 28 73 74 61 72 74 65 s posted (starte
3f20: 64 2c 20 6b 65 70 74 20 6c 6f 67 73 2c 20 65 6e d, kept logs, en
3f30: 64 65 64 29 22 0a 24 46 20 73 71 6c 20 2d 52 20 ded)".$F sql -R
3f40: 24 52 20 22 53 45 4c 45 43 54 20 73 75 62 73 74 $R "SELECT subst
3f50: 72 28 62 2e 75 75 69 64 2c 31 2c 31 30 29 2c 20 r(b.uuid,1,10),
3f60: 75 2e 6c 6f 67 69 6e 2c 20 73 75 62 73 74 72 28 u.login, substr(
3f70: 72 65 70 6c 61 63 65 28 72 65 70 6c 61 63 65 28 replace(replace(
3f80: 43 41 53 54 28 63 6f 6e 74 65 6e 74 28 62 2e 75 CAST(content(b.u
3f90: 75 69 64 29 20 41 53 20 54 45 58 54 29 2c 63 68 uid) AS TEXT),ch
3fa0: 61 72 28 31 30 29 2c 27 20 27 29 2c 27 20 20 27 ar(10),' '),' '
3fb0: 2c 27 20 27 29 2c 31 2c 36 30 30 29 20 46 52 4f ,' '),1,600) FRO
3fc0: 4d 20 66 6f 72 75 6d 70 6f 73 74 20 66 20 4a 4f M forumpost f JO
3fd0: 49 4e 20 62 6c 6f 62 20 62 20 4f 4e 20 62 2e 72 IN blob b ON b.r
3fe0: 69 64 3d 66 2e 66 70 69 64 20 4c 45 46 54 20 4a id=f.fpid LEFT J
3ff0: 4f 49 4e 20 72 63 76 66 72 6f 6d 20 72 20 4f 4e OIN rcvfrom r ON
4000: 20 72 2e 72 63 76 69 64 3d 62 2e 72 63 76 69 64 r.rcvid=b.rcvid
4010: 20 4c 45 46 54 20 4a 4f 49 4e 20 75 73 65 72 20 LEFT JOIN user
4020: 75 20 4f 4e 20 75 2e 75 69 64 3d 72 2e 75 69 64 u ON u.uid=r.uid
4030: 20 4f 52 44 45 52 20 42 59 20 66 2e 66 6d 74 69 ORDER BY f.fmti
4040: 6d 65 22 20 7c 20 74 61 69 6c 20 2d 6e 20 2b 31 me" | tail -n +1
4050: 0a 0a 73 61 79 20 22 72 65 63 65 69 70 74 73 20 ..say "receipts
4060: 74 68 72 6f 75 67 68 20 74 68 65 20 6c 61 75 6e through the laun
4070: 63 68 65 72 27 73 20 43 47 49 20 72 6f 75 74 65 cher's CGI route
4080: 2c 20 61 67 61 69 6e 73 74 20 46 6f 73 73 69 6c , against Fossil
4090: 27 73 20 6f 77 6e 20 72 65 63 6f 72 64 22 0a 48 's own record".H
40a0: 31 3d 24 28 24 46 20 73 71 6c 20 2d 52 20 24 52 1=$($F sql -R $R
40b0: 20 22 53 45 4c 45 43 54 20 62 2e 75 75 69 64 20 "SELECT b.uuid
40c0: 46 52 4f 4d 20 62 6c 6f 62 20 62 20 4a 4f 49 4e FROM blob b JOIN
40d0: 20 66 6f 72 75 6d 70 6f 73 74 20 66 20 4f 4e 20 forumpost f ON
40e0: 66 2e 66 70 69 64 3d 62 2e 72 69 64 20 4f 52 44 f.fpid=b.rid ORD
40f0: 45 52 20 42 59 20 66 2e 66 6d 74 69 6d 65 20 4c ER BY f.fmtime L
4100: 49 4d 49 54 20 31 22 20 7c 20 74 72 20 2d 64 20 IMIT 1" | tr -d
4110: 22 27 22 29 0a 66 6f 72 20 77 68 6f 20 69 6e 20 "'").for who in
4120: 22 62 6f 73 73 20 62 6f 73 73 2d 70 77 22 20 22 "boss boss-pw" "
4130: 76 69 65 77 65 72 20 76 69 65 77 65 72 2d 70 77 viewer viewer-pw
4140: 22 20 22 61 6e 6f 6e 20 2d 22 3b 20 64 6f 20 73 " "anon -"; do s
4150: 65 74 20 2d 2d 20 24 77 68 6f 0a 20 20 70 79 74 et -- $who. pyt
4160: 68 6f 6e 33 20 2d 20 22 24 55 22 20 22 24 31 22 hon3 - "$U" "$1"
4170: 20 22 24 32 22 20 22 24 48 31 22 20 3c 3c 27 45 "$2" "$H1" <<'E
4180: 27 0a 69 6d 70 6f 72 74 20 68 74 74 70 2e 63 6f '.import http.co
4190: 6f 6b 69 65 6a 61 72 2c 20 6a 73 6f 6e 2c 20 73 okiejar, json, s
41a0: 79 73 2c 20 75 72 6c 6c 69 62 2e 70 61 72 73 65 ys, urllib.parse
41b0: 2c 20 75 72 6c 6c 69 62 2e 72 65 71 75 65 73 74 , urllib.request
41c0: 0a 62 61 73 65 2c 20 75 73 65 72 2c 20 70 77 2c .base, user, pw,
41d0: 20 68 20 3d 20 73 79 73 2e 61 72 67 76 5b 31 3a h = sys.argv[1:
41e0: 35 5d 0a 6a 61 72 20 3d 20 68 74 74 70 2e 63 6f 5].jar = http.co
41f0: 6f 6b 69 65 6a 61 72 2e 43 6f 6f 6b 69 65 4a 61 okiejar.CookieJa
4200: 72 28 29 3b 20 6f 70 20 3d 20 75 72 6c 6c 69 62 r(); op = urllib
4210: 2e 72 65 71 75 65 73 74 2e 62 75 69 6c 64 5f 6f .request.build_o
4220: 70 65 6e 65 72 28 75 72 6c 6c 69 62 2e 72 65 71 pener(urllib.req
4230: 75 65 73 74 2e 48 54 54 50 43 6f 6f 6b 69 65 50 uest.HTTPCookieP
4240: 72 6f 63 65 73 73 6f 72 28 6a 61 72 29 29 0a 69 rocessor(jar)).i
4250: 66 20 70 77 20 21 3d 20 22 2d 22 3a 20 6f 70 2e f pw != "-": op.
4260: 6f 70 65 6e 28 62 61 73 65 20 2b 20 22 2f 6c 6f open(base + "/lo
4270: 67 69 6e 22 2c 20 75 72 6c 6c 69 62 2e 70 61 72 gin", urllib.par
4280: 73 65 2e 75 72 6c 65 6e 63 6f 64 65 28 7b 22 75 se.urlencode({"u
4290: 22 3a 20 75 73 65 72 2c 20 22 70 22 3a 20 70 77 ": user, "p": pw
42a0: 2c 20 22 69 6e 22 3a 20 22 31 22 7d 29 2e 65 6e , "in": "1"}).en
42b0: 63 6f 64 65 28 29 29 0a 74 72 79 3a 0a 20 20 20 code()).try:.
42c0: 20 72 20 3d 20 6f 70 2e 6f 70 65 6e 28 62 61 73 r = op.open(bas
42d0: 65 20 2b 20 22 2f 65 78 74 2f 6f 63 78 32 2d 63 e + "/ext/ocx2-c
42e0: 67 69 2f 72 65 63 65 69 70 74 22 2c 20 75 72 6c gi/receipt", url
42f0: 6c 69 62 2e 70 61 72 73 65 2e 75 72 6c 65 6e 63 lib.parse.urlenc
4300: 6f 64 65 28 7b 22 6a 73 6f 6e 22 3a 20 22 6f 6e ode({"json": "on
4310: 22 2c 20 22 61 72 74 69 66 61 63 74 73 22 3a 20 ", "artifacts":
4320: 68 2c 20 22 63 61 70 61 62 69 6c 69 74 69 65 73 h, "capabilities
4330: 5f 6f 66 22 3a 20 22 64 65 6d 6f 2d 6e 6f 64 65 _of": "demo-node
4340: 22 7d 29 2e 65 6e 63 6f 64 65 28 29 29 0a 20 20 "}).encode()).
4350: 20 20 61 20 3d 20 6a 73 6f 6e 2e 6c 6f 61 64 28 a = json.load(
4360: 72 29 0a 65 78 63 65 70 74 20 75 72 6c 6c 69 62 r).except urllib
4370: 2e 65 72 72 6f 72 2e 48 54 54 50 45 72 72 6f 72 .error.HTTPError
4380: 20 61 73 20 65 3a 0a 20 20 20 20 61 20 3d 20 7b as e:. a = {
4390: 22 68 74 74 70 22 3a 20 65 2e 63 6f 64 65 2c 20 "http": e.code,
43a0: 22 62 6f 64 79 22 3a 20 65 2e 72 65 61 64 28 29 "body": e.read()
43b0: 2e 64 65 63 6f 64 65 28 29 5b 3a 33 30 30 5d 7d .decode()[:300]}
43c0: 0a 70 72 69 6e 74 28 75 73 65 72 2c 20 6a 73 6f .print(user, jso
43d0: 6e 2e 64 75 6d 70 73 28 61 2e 67 65 74 28 22 72 n.dumps(a.get("r
43e0: 65 73 75 6c 74 22 2c 20 61 29 29 29 0a 45 0a 64 esult", a))).E.d
43f0: 6f 6e 65 0a 65 63 68 6f 20 22 46 6f 73 73 69 6c one.echo "Fossil
4400: 27 73 20 6f 77 6e 20 72 65 63 6f 72 64 3a 20 24 's own record: $
4410: 28 24 46 20 73 71 6c 20 2d 52 20 24 52 20 22 53 ($F sql -R $R "S
4420: 45 4c 45 43 54 20 75 2e 6c 6f 67 69 6e 2c 20 66 ELECT u.login, f
4430: 75 6c 6c 63 61 70 28 75 2e 63 61 70 29 2c 20 62 ullcap(u.cap), b
4440: 2e 72 63 76 69 64 2c 20 62 2e 72 69 64 20 46 52 .rcvid, b.rid FR
4450: 4f 4d 20 62 6c 6f 62 20 62 20 4a 4f 49 4e 20 72 OM blob b JOIN r
4460: 63 76 66 72 6f 6d 20 72 20 55 53 49 4e 47 28 72 cvfrom r USING(r
4470: 63 76 69 64 29 20 4a 4f 49 4e 20 75 73 65 72 20 cvid) JOIN user
4480: 75 20 55 53 49 4e 47 28 75 69 64 29 20 57 48 45 u USING(uid) WHE
4490: 52 45 20 62 2e 75 75 69 64 3d 27 24 48 31 27 22 RE b.uuid='$H1'"
44a0: 29 22 0a 65 63 68 6f 20 22 46 6f 73 73 69 6c 27 )".echo "Fossil'
44b0: 73 20 66 75 6c 6c 63 61 70 28 64 65 6d 6f 2d 6e s fullcap(demo-n
44c0: 6f 64 65 29 3a 20 24 28 24 46 20 73 71 6c 20 2d ode): $($F sql -
44d0: 52 20 24 52 20 22 53 45 4c 45 43 54 20 66 75 6c R $R "SELECT ful
44e0: 6c 63 61 70 28 63 61 70 29 20 46 52 4f 4d 20 75 lcap(cap) FROM u
44f0: 73 65 72 20 57 48 45 52 45 20 6c 6f 67 69 6e 3d ser WHERE login=
4500: 27 64 65 6d 6f 2d 6e 6f 64 65 27 22 29 22 0a 0a 'demo-node'")"..
4510: 73 61 79 20 22 74 68 65 20 63 6f 6e 73 6f 6c 65 say "the console
4520: 2c 20 61 73 20 62 6f 73 73 20 28 74 68 65 20 70 , as boss (the p
4530: 61 67 65 27 73 20 6f 74 68 65 72 20 70 61 74 68 age's other path
4540: 73 20 73 74 69 6c 6c 20 70 61 73 73 20 74 68 72 s still pass thr
4550: 6f 75 67 68 3a 20 45 36 29 22 0a 70 79 74 68 6f ough: E6)".pytho
4560: 6e 33 20 2d 20 22 24 55 22 20 3c 3c 27 45 27 0a n3 - "$U" <<'E'.
4570: 69 6d 70 6f 72 74 20 68 74 74 70 2e 63 6f 6f 6b import http.cook
4580: 69 65 6a 61 72 2c 20 73 79 73 2c 20 75 72 6c 6c iejar, sys, urll
4590: 69 62 2e 70 61 72 73 65 2c 20 75 72 6c 6c 69 62 ib.parse, urllib
45a0: 2e 72 65 71 75 65 73 74 0a 62 61 73 65 20 3d 20 .request.base =
45b0: 73 79 73 2e 61 72 67 76 5b 31 5d 0a 6a 61 72 20 sys.argv[1].jar
45c0: 3d 20 68 74 74 70 2e 63 6f 6f 6b 69 65 6a 61 72 = http.cookiejar
45d0: 2e 43 6f 6f 6b 69 65 4a 61 72 28 29 3b 20 6f 70 .CookieJar(); op
45e0: 20 3d 20 75 72 6c 6c 69 62 2e 72 65 71 75 65 73 = urllib.reques
45f0: 74 2e 62 75 69 6c 64 5f 6f 70 65 6e 65 72 28 75 t.build_opener(u
4600: 72 6c 6c 69 62 2e 72 65 71 75 65 73 74 2e 48 54 rllib.request.HT
4610: 54 50 43 6f 6f 6b 69 65 50 72 6f 63 65 73 73 6f TPCookieProcesso
4620: 72 28 6a 61 72 29 29 0a 6f 70 2e 6f 70 65 6e 28 r(jar)).op.open(
4630: 62 61 73 65 20 2b 20 22 2f 6c 6f 67 69 6e 22 2c base + "/login",
4640: 20 75 72 6c 6c 69 62 2e 70 61 72 73 65 2e 75 72 urllib.parse.ur
4650: 6c 65 6e 63 6f 64 65 28 7b 22 75 22 3a 20 22 62 lencode({"u": "b
4660: 6f 73 73 22 2c 20 22 70 22 3a 20 22 62 6f 73 73 oss", "p": "boss
4670: 2d 70 77 22 2c 20 22 69 6e 22 3a 20 22 31 22 7d -pw", "in": "1"}
4680: 29 2e 65 6e 63 6f 64 65 28 29 29 0a 72 20 3d 20 ).encode()).r =
4690: 6f 70 2e 6f 70 65 6e 28 62 61 73 65 20 2b 20 22 op.open(base + "
46a0: 2f 65 78 74 2f 6f 63 78 32 2d 63 67 69 2f 63 6f /ext/ocx2-cgi/co
46b0: 6e 73 6f 6c 65 3f 6a 73 6f 6e 3d 6f 6e 22 29 3b nsole?json=on");
46c0: 20 69 6d 70 6f 72 74 20 6a 73 6f 6e 3b 20 61 20 import json; a
46d0: 3d 20 6a 73 6f 6e 2e 6c 6f 61 64 28 72 29 0a 72 = json.load(r).r
46e0: 65 73 20 3d 20 61 2e 67 65 74 28 22 72 65 73 75 es = a.get("resu
46f0: 6c 74 22 29 20 6f 72 20 7b 7d 0a 70 72 69 6e 74 lt") or {}.print
4700: 28 22 63 6f 6e 73 6f 6c 65 20 6f 6b 3a 22 2c 20 ("console ok:",
4710: 61 2e 67 65 74 28 22 73 74 6f 70 70 65 64 22 29 a.get("stopped")
4720: 20 69 73 20 4e 6f 6e 65 2c 20 22 7c 20 72 75 6e is None, "| run
4730: 73 20 72 75 6e 6e 69 6e 67 3a 22 2c 20 6c 65 6e s running:", len
4740: 28 72 65 73 2e 67 65 74 28 22 72 75 6e 6e 69 6e (res.get("runnin
4750: 67 22 2c 20 5b 5d 29 29 2c 20 22 7c 20 65 6e 64 g", [])), "| end
4760: 65 64 3a 22 2c 20 6c 65 6e 28 72 65 73 2e 67 65 ed:", len(res.ge
4770: 74 28 22 65 6e 64 65 64 22 2c 20 5b 5d 29 29 29 t("ended", [])))
4780: 0a 45 0a 0a 73 61 79 20 22 77 72 69 74 65 73 20 .E..say "writes
4790: 66 72 6f 6d 20 74 68 65 20 72 65 63 65 69 70 74 from the receipt
47a0: 20 73 65 72 76 69 63 65 27 73 20 70 6f 6c 69 63 service's polic
47b0: 79 20 66 61 69 6c 20 28 61 20 70 72 6f 62 65 20 y fail (a probe
47c0: 69 6e 20 70 6c 61 63 65 20 6f 66 20 72 65 63 65 in place of rece
47d0: 69 70 74 73 29 22 0a 50 42 3d 24 4f 55 54 2f 70 ipts)".PB=$OUT/p
47e0: 72 6f 62 65 3b 20 6d 6b 64 69 72 20 2d 70 20 24 robe; mkdir -p $
47f0: 50 42 3b 20 63 70 20 24 42 49 4e 2f 73 74 61 72 PB; cp $BIN/star
4800: 74 2d 6f 63 78 20 24 50 42 2f 73 74 61 72 74 2d t-ocx $PB/start-
4810: 6f 63 78 0a 63 61 74 20 3e 20 24 4f 55 54 2f 70 ocx.cat > $OUT/p
4820: 72 6f 62 65 2e 63 72 20 3c 3c 27 45 27 0a 72 65 robe.cr <<'E'.re
4830: 71 75 69 72 65 20 22 73 6f 63 6b 65 74 22 0a 73 quire "socket".s
4840: 6f 63 6b 65 74 2c 20 64 69 72 20 3d 20 41 52 47 ocket, dir = ARG
4850: 56 0a 72 65 70 6f 20 3d 20 44 69 72 2e 63 68 69 V.repo = Dir.chi
4860: 6c 64 72 65 6e 28 64 69 72 29 2e 66 69 6e 64 28 ldren(dir).find(
4870: 26 2e 65 6e 64 73 5f 77 69 74 68 3f 28 22 2e 66 &.ends_with?(".f
4880: 6f 73 73 69 6c 22 29 29 2e 6e 6f 74 5f 6e 69 6c ossil")).not_nil
4890: 21 0a 70 61 74 68 20 3d 20 46 69 6c 65 2e 6a 6f !.path = File.jo
48a0: 69 6e 28 64 69 72 2c 20 72 65 70 6f 29 0a 74 72 in(dir, repo).tr
48b0: 69 65 73 20 3d 20 7b 0a 20 20 22 6f 70 65 6e 20 ies = {. "open
48c0: 74 68 65 20 72 65 70 6f 73 69 74 6f 72 79 20 66 the repository f
48d0: 6f 72 20 77 72 69 74 69 6e 67 22 20 3d 3e 20 2d or writing" => -
48e0: 3e 20 7b 20 46 69 6c 65 2e 6f 70 65 6e 28 70 61 > { File.open(pa
48f0: 74 68 2c 20 22 72 2b 22 29 20 7b 20 7d 3b 20 22 th, "r+") { }; "
4900: 4f 50 45 4e 45 44 20 28 62 61 64 29 22 20 7d 2c OPENED (bad)" },
4910: 0a 20 20 22 63 72 65 61 74 65 20 61 20 66 69 6c . "create a fil
4920: 65 20 62 65 73 69 64 65 20 69 74 22 20 20 20 20 e beside it"
4930: 20 20 20 20 20 3d 3e 20 2d 3e 20 7b 20 46 69 6c => -> { Fil
4940: 65 2e 77 72 69 74 65 28 46 69 6c 65 2e 6a 6f 69 e.write(File.joi
4950: 6e 28 64 69 72 2c 20 22 78 22 29 2c 20 22 78 22 n(dir, "x"), "x"
4960: 29 3b 20 22 43 52 45 41 54 45 44 20 28 62 61 64 ); "CREATED (bad
4970: 29 22 20 7d 2c 0a 20 20 22 72 65 61 64 20 74 68 )" },. "read th
4980: 65 20 72 65 70 6f 73 69 74 6f 72 79 22 20 20 20 e repository"
4990: 20 20 20 20 20 20 20 20 20 20 3d 3e 20 2d 3e 20 => ->
49a0: 7b 20 46 69 6c 65 2e 6f 70 65 6e 28 70 61 74 68 { File.open(path
49b0: 29 20 7b 20 7c 66 7c 20 66 2e 72 65 61 64 5f 62 ) { |f| f.read_b
49c0: 79 74 65 20 7d 3b 20 22 72 65 61 64 20 6f 6b 20 yte }; "read ok
49d0: 28 61 6c 6c 6f 77 65 64 3a 20 72 65 61 64 2d 6f (allowed: read-o
49e0: 6e 6c 79 29 22 20 7d 2c 0a 20 20 22 72 65 61 63 nly)" },. "reac
49f0: 68 20 46 6f 73 73 69 6c 27 73 20 70 6f 72 74 22 h Fossil's port"
4a00: 20 20 20 20 20 20 20 20 20 20 20 20 20 3d 3e 20 =>
4a10: 2d 3e 20 7b 20 54 43 50 53 6f 63 6b 65 74 2e 6e -> { TCPSocket.n
4a20: 65 77 28 22 31 32 37 2e 30 2e 30 2e 31 22 2c 20 ew("127.0.0.1",
4a30: 46 69 6c 65 2e 72 65 61 64 28 46 69 6c 65 2e 6a File.read(File.j
4a40: 6f 69 6e 28 46 69 6c 65 2e 64 69 72 6e 61 6d 65 oin(File.dirname
4a50: 28 73 6f 63 6b 65 74 29 2c 20 22 70 6f 72 74 22 (socket), "port"
4a60: 29 29 2e 73 74 72 69 70 2e 74 6f 5f 69 2c 20 63 )).strip.to_i, c
4a70: 6f 6e 6e 65 63 74 5f 74 69 6d 65 6f 75 74 3a 20 onnect_timeout:
4a80: 32 2e 73 65 63 6f 6e 64 73 29 2e 63 6c 6f 73 65 2.seconds).close
4a90: 3b 20 22 43 4f 4e 4e 45 43 54 45 44 20 28 62 61 ; "CONNECTED (ba
4aa0: 64 29 22 20 7d 2c 0a 20 20 22 77 72 69 74 65 20 d)" },. "write
4ab0: 69 6e 20 69 74 73 20 73 6f 63 6b 65 74 20 64 69 in its socket di
4ac0: 72 65 63 74 6f 72 79 22 20 20 20 3d 3e 20 2d 3e rectory" => ->
4ad0: 20 7b 20 46 69 6c 65 2e 77 72 69 74 65 28 46 69 { File.write(Fi
4ae0: 6c 65 2e 6a 6f 69 6e 28 46 69 6c 65 2e 64 69 72 le.join(File.dir
4af0: 6e 61 6d 65 28 73 6f 63 6b 65 74 29 2c 20 22 70 name(socket), "p
4b00: 72 6f 62 65 22 29 2c 20 22 78 22 29 3b 20 22 77 robe"), "x"); "w
4b10: 72 69 74 74 65 6e 20 28 61 6c 6c 6f 77 65 64 3a ritten (allowed:
4b20: 20 69 74 73 20 6f 6e 65 20 77 72 69 74 61 62 6c its one writabl
4b30: 65 20 70 6c 61 63 65 29 22 20 7d 2c 0a 7d 0a 74 e place)" },.}.t
4b40: 72 69 65 73 2e 65 61 63 68 20 64 6f 20 7c 77 68 ries.each do |wh
4b50: 61 74 2c 20 74 72 79 7c 0a 20 20 6f 75 74 63 6f at, try|. outco
4b60: 6d 65 20 3d 20 62 65 67 69 6e 0a 20 20 20 20 74 me = begin. t
4b70: 72 79 2e 63 61 6c 6c 0a 20 20 72 65 73 63 75 65 ry.call. rescue
4b80: 20 65 0a 20 20 20 20 22 72 65 66 75 73 65 64 20 e. "refused
4b90: 28 23 7b 65 2e 63 6c 61 73 73 7d 3a 20 23 7b 65 (#{e.class}: #{e
4ba0: 2e 6d 65 73 73 61 67 65 2e 74 72 79 20 26 2e 6c .message.try &.l
4bb0: 69 6e 65 73 2e 66 69 72 73 74 7d 29 22 0a 20 20 ines.first})".
4bc0: 65 6e 64 0a 20 20 70 75 74 73 20 22 23 7b 77 68 end. puts "#{wh
4bd0: 61 74 7d 3a 20 23 7b 6f 75 74 63 6f 6d 65 7d 22 at}: #{outcome}"
4be0: 0a 65 6e 64 0a 45 0a 65 63 68 6f 20 24 50 20 3e .end.E.echo $P >
4bf0: 20 24 44 2f 72 75 6e 2f 70 6f 72 74 3b 20 63 75 $D/run/port; cu
4c00: 72 6c 20 2d 73 20 2d 6f 20 2f 64 65 76 2f 6e 75 rl -s -o /dev/nu
4c10: 6c 6c 20 2d 77 20 22 46 6f 73 73 69 6c 27 73 20 ll -w "Fossil's
4c20: 70 6f 72 74 20 24 50 20 61 6e 73 77 65 72 73 20 port $P answers
4c30: 6f 6e 20 74 68 65 20 68 6f 73 74 3a 20 25 7b 68 on the host: %{h
4c40: 74 74 70 5f 63 6f 64 65 7d 5c 6e 22 20 68 74 74 ttp_code}\n" htt
4c50: 70 3a 2f 2f 31 32 37 2e 30 2e 30 2e 31 3a 24 50 p://127.0.0.1:$P
4c60: 2f 3b 20 6e 69 63 65 20 2d 6e 20 31 39 20 63 72 /; nice -n 19 cr
4c70: 79 73 74 61 6c 20 62 75 69 6c 64 20 2d 6f 20 24 ystal build -o $
4c80: 50 42 2f 72 65 63 65 69 70 74 73 20 24 4f 55 54 PB/receipts $OUT
4c90: 2f 70 72 6f 62 65 2e 63 72 20 3e 2f 64 65 76 2f /probe.cr >/dev/
4ca0: 6e 75 6c 6c 20 26 26 20 74 69 6d 65 6f 75 74 20 null && timeout
4cb0: 36 30 20 24 50 42 2f 73 74 61 72 74 2d 6f 63 78 60 $PB/start-ocx
4cc0: 20 2d 2d 73 63 72 61 74 63 68 20 24 44 20 72 65 --scratch $D re
4cd0: 63 65 69 70 74 73 0a 0a 73 61 79 20 22 74 68 65 ceipts..say "the
4ce0: 20 64 61 65 6d 6f 6e 27 73 20 6f 77 6e 20 76 69 daemon's own vi
4cf0: 65 77 3a 20 61 20 70 72 6f 62 65 20 69 6e 20 70 ew: a probe in p
4d00: 6c 61 63 65 20 6f 66 20 69 74 73 20 70 72 6f 67 lace of its prog
4d10: 72 61 6d 2c 20 73 74 61 72 74 65 64 20 74 68 72 ram, started thr
4d20: 6f 75 67 68 20 74 68 65 20 73 61 6d 65 20 64 61 ough the same da
4d30: 65 6d 6f 6e 20 70 6f 6c 69 63 79 22 0a 6b 69 6c emon policy".kil
4d40: 6c 20 24 7b 70 69 64 73 5b 32 5d 7d 20 32 3e 2f l ${pids[2]} 2>/
4d50: 64 65 76 2f 6e 75 6c 6c 3b 20 73 6c 65 65 70 20 dev/null; sleep
4d60: 31 0a 6d 6b 64 69 72 20 2d 70 20 24 44 2f 64 61 1.mkdir -p $D/da
4d70: 65 6d 6f 6e 2f 70 72 6f 62 65 30 30 30 30 30 30 emon/probe000000
4d80: 30 31 0a 70 72 69 6e 74 66 20 27 23 21 2f 62 69 01.printf '#!/bi
4d90: 6e 2f 73 68 5c 6e 65 63 68 6f 20 22 64 61 65 6d n/sh\necho "daem
4da0: 6f 6e 20 70 72 6f 62 65 3a 20 75 69 64 3d 24 28 on probe: uid=$(
4db0: 69 64 20 2d 75 29 20 63 61 70 73 3d 24 28 67 72 id -u) caps=$(gr
4dc0: 65 70 20 43 61 70 45 66 66 20 2f 70 72 6f 63 2f ep CapEff /proc/
4dd0: 73 65 6c 66 2f 73 74 61 74 75 73 20 7c 20 74 72 self/status | tr
4de0: 20 2d 73 20 22 5c 74 20 22 20 22 20 22 29 22 5c -s "\t " " ")"\
4df0: 6e 66 6f 72 20 70 20 69 6e 20 25 73 20 25 73 3b nfor p in %s %s;
4e00: 20 64 6f 20 5b 20 2d 65 20 24 70 20 5d 20 26 26 do [ -e $p ] &&
4e10: 20 65 63 68 6f 20 22 56 49 53 49 42 4c 45 20 24 echo "VISIBLE $
4e20: 70 22 20 7c 7c 20 65 63 68 6f 20 22 61 62 73 65 p" || echo "abse
4e30: 6e 74 20 24 70 22 3b 20 64 6f 6e 65 5c 6e 6e 3d nt $p"; done\nn=
4e40: 30 3b 20 66 6f 72 20 78 20 69 6e 20 2f 70 72 6f 0; for x in /pro
4e50: 63 2f 5b 30 2d 39 5d 2a 2f 72 6f 6f 74 25 73 3b c/[0-9]*/root%s;
4e60: 20 64 6f 20 5b 20 2d 72 20 24 78 20 5d 20 26 26 do [ -r $x ] &&
4e70: 20 6e 3d 24 28 28 6e 2b 31 29 29 3b 20 64 6f 6e n=$((n+1)); don
4e80: 65 3b 20 65 63 68 6f 20 22 70 72 6f 63 2d 70 61 e; echo "proc-pa
4e90: 74 68 73 2d 72 65 61 64 61 62 6c 65 3d 24 6e 20 ths-readable=$n
4ea0: 28 6f 74 68 65 72 20 70 72 6f 63 65 73 73 65 73 (other processes
4eb0: 20 6f 66 20 74 68 65 20 73 61 6d 65 20 61 63 63 of the same acc
4ec0: 6f 75 6e 74 3b 20 74 68 65 20 6c 69 76 65 20 64 ount; the live d
4ed0: 61 65 6d 6f 6e 20 68 61 73 20 61 6e 20 61 63 63 aemon has an acc
4ee0: 6f 75 6e 74 20 6f 66 20 69 74 73 20 6f 77 6e 29 ount of its own)
4ef0: 22 5c 6e 62 77 72 61 70 20 2d 2d 75 6e 73 68 61 "\nbwrap --unsha
4f00: 72 65 2d 61 6c 6c 20 2d 2d 72 6f 2d 62 69 6e 64 re-all --ro-bind
4f10: 20 2f 75 73 72 20 2f 75 73 72 20 2d 2d 72 6f 2d /usr /usr --ro-
4f20: 62 69 6e 64 2d 74 72 79 20 2f 6c 69 62 20 2f 6c bind-try /lib /l
4f30: 69 62 20 2d 2d 72 6f 2d 62 69 6e 64 2d 74 72 79 ib --ro-bind-try
4f40: 20 2f 6c 69 62 36 34 20 2f 6c 69 62 36 34 20 2d /lib64 /lib64 -
4f50: 2d 72 6f 2d 62 69 6e 64 20 2f 62 69 6e 20 2f 62 -ro-bind /bin /b
4f60: 69 6e 20 2d 2d 70 72 6f 63 20 2f 70 72 6f 63 20 in --proc /proc
4f70: 2d 2d 64 65 76 20 2f 64 65 76 20 2f 62 69 6e 2f --dev /dev /bin/
4f80: 73 68 20 2d 63 20 22 65 63 68 6f 20 61 67 65 6e sh -c "echo agen
4f90: 74 20 73 61 6e 64 62 6f 78 20 69 6e 73 69 64 65 t sandbox inside
4fa0: 3a 20 73 74 61 72 74 65 64 22 20 32 3e 26 31 5c : started" 2>&1\
4fb0: 6e 27 20 24 44 2f 66 6f 73 73 69 6c 20 24 52 20 n' $D/fossil $R
4fc0: 24 52 20 3e 20 24 44 2f 64 61 65 6d 6f 6e 2f 70 $R > $D/daemon/p
4fd0: 72 6f 62 65 30 30 30 30 30 30 30 31 2f 6f 63 78 robe00000001/ocx
4fe0: 32 3b 20 63 68 6d 6f 64 20 37 35 35 20 24 44 2f 2; chmod 755 $D/
4ff0: 64 61 65 6d 6f 6e 2f 70 72 6f 62 65 30 30 30 30 daemon/probe0000
5000: 30 30 30 31 2f 6f 63 78 32 0a 6c 6e 20 2d 73 66 0001/ocx2.ln -sf
5010: 6e 20 70 72 6f 62 65 30 30 30 30 30 30 30 31 20 n probe00000001
5020: 24 44 2f 64 61 65 6d 6f 6e 2f 63 75 72 72 65 6e $D/daemon/curren
5030: 74 0a 74 69 6d 65 6f 75 74 20 33 30 20 24 42 49 t.timeout 30 $BI
5040: 4e 2f 73 74 61 72 74 2d 6f 63 78 20 2d 2d 73 63 N/start-ocx --sc
5050: 72 61 74 63 68 20 24 44 20 64 61 65 6d 6f 6e 0a ratch $D daemon.
5060: 6c 6e 20 2d 73 66 6e 20 24 52 45 4c 20 24 44 2f ln -sfn $REL $D/
5070: 64 61 65 6d 6f 6e 2f 63 75 72 72 65 6e 74 0a 0a daemon/current..
5080: 73 61 79 20 22 72 6f 6c 6c 62 61 63 6b 20 70 6f say "rollback po
5090: 69 6e 74 3a 20 74 68 65 20 6c 61 75 6e 63 68 65 int: the launche
50a0: 72 27 73 20 43 47 49 20 6c 69 6e 6b 20 69 73 20 r's CGI link is
50b0: 6f 6e 65 20 66 69 6c 65 3b 20 74 68 65 20 70 72 one file; the pr
50c0: 65 76 69 6f 75 73 20 70 61 67 65 20 69 73 20 74 evious page is t
50d0: 68 65 20 72 65 6c 65 61 73 65 27 73 20 6f 77 6e he release's own
50e0: 20 6f 63 78 32 22 0a 6c 73 20 2d 6c 20 24 44 2f ocx2".ls -l $D/
50f0: 65 78 74 2f 6f 63 78 32 2d 63 67 69 0a 65 63 68 ext/ocx2-cgi.ech
5100: 6f 20 22 64 6f 6e 65 22 0a 00 00 00 00 00 00 00 o "done"........
5110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
51a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
51b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
51c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
51d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
51e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
51f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5200: 73 74 61 67 65 41 2d 72 65 63 6f 72 64 2f 73 74 stageA-record/st
5210: 61 67 65 41 2d 70 6c 61 6e 2e 6d 64 00 00 00 00 ageA-plan.md....
5220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5260: 00 00 00 00 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000
5270: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
5280: 30 30 32 36 32 36 33 00 31 35 32 37 30 34 37 36 0026263.15270476
5290: 32 30 35 00 30 31 34 37 33 33 00 20 30 00 00 00 205.014733. 0...
52a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
52b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
52c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
52d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
52e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
52f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5300: 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
5310: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5320: 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
5330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
53a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
53b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
53c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
53d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
53e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
53f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5400: 23 20 53 74 61 67 65 20 41 3a 20 74 68 65 20 72 # Stage A: the r
5410: 65 63 65 69 70 74 20 73 65 72 76 69 63 65 20 61 eceipt service a
5420: 6e 64 20 74 68 65 20 6c 61 75 6e 63 68 65 72 20 nd the launcher
5430: 28 74 77 6f 20 66 69 6c 65 73 20 69 6e 20 73 63 (two files in sc
5440: 72 69 70 74 73 2f 29 0a 0a 57 72 69 74 65 20 74 ripts/)..Write t
5450: 77 6f 20 6e 65 77 2c 20 73 65 6c 66 2d 63 6f 6e wo new, self-con
5460: 74 61 69 6e 65 64 20 43 72 79 73 74 61 6c 20 70 tained Crystal p
5470: 72 6f 67 72 61 6d 73 20 69 6e 20 60 73 63 72 69 rograms in `scri
5480: 70 74 73 2f 60 2c 20 70 6c 75 73 20 74 68 65 0a pts/`, plus the.
5490: 60 73 68 61 72 64 2e 79 6d 6c 60 20 74 61 72 67 `shard.yml` targ
54a0: 65 74 73 20 74 68 61 74 20 62 75 69 6c 64 20 74 ets that build t
54b0: 68 65 6d 2e 20 52 65 61 64 20 60 73 63 72 69 70 hem. Read `scrip
54c0: 74 73 2f 73 74 61 72 74 2d 66 6f 73 73 69 6c 2e ts/start-fossil.
54d0: 63 72 60 20 66 69 72 73 74 3a 0a 74 68 65 73 65 cr` first:.these
54e0: 20 66 6f 6c 6c 6f 77 20 69 74 73 20 66 6f 72 6d follow its form
54f0: 20 28 64 65 63 69 73 69 6f 6e 20 32 32 20 69 6e (decision 22 in
5500: 20 48 49 53 54 4f 52 59 2e 6d 64 29 2e 0a 2d 20 HISTORY.md)..-
5510: 41 20 63 6f 6d 6d 65 6e 74 20 61 74 20 74 68 65 A comment at the
5520: 20 74 6f 70 20 73 61 79 73 20 22 41 67 65 6e 74 top says "Agent
5530: 73 3a 20 64 6f 20 6e 6f 74 20 63 68 61 6e 67 65 s: do not change
5540: 20 74 68 69 73 20 66 69 6c 65 20 6f 6e 20 61 6e this file on an
5550: 79 20 62 72 61 6e 63 68 0a 20 20 77 69 74 68 6f y branch. witho
5560: 75 74 20 74 68 65 20 6d 61 69 6e 74 61 69 6e 65 ut the maintaine
5570: 72 27 73 20 65 78 70 6c 69 63 69 74 20 61 70 70 r's explicit app
5580: 72 6f 76 61 6c 20 6f 6e 20 74 68 65 20 72 65 63 roval on the rec
5590: 6f 72 64 2e 22 0a 2d 20 45 61 63 68 20 66 69 6c ord.".- Each fil
55a0: 65 20 73 74 61 74 65 73 20 65 76 65 72 79 74 68 e states everyth
55b0: 69 6e 67 20 69 74 20 64 6f 65 73 2e 20 50 61 74 ing it does. Pat
55c0: 68 73 20 61 72 65 20 63 6f 6e 73 74 61 6e 74 73 hs are constants
55d0: 20 69 6e 20 74 68 65 20 66 69 6c 65 2c 0a 20 20 in the file,.
55e0: 63 68 6f 73 65 6e 20 62 79 20 68 6f 73 74 20 6e chosen by host n
55f0: 61 6d 65 2e 0a 2d 20 45 61 63 68 20 66 69 6c 65 ame..- Each file
5600: 20 75 73 65 73 20 43 72 79 73 74 61 6c 27 73 20 uses Crystal's
5610: 73 74 61 6e 64 61 72 64 20 6c 69 62 72 61 72 79 standard library
5620: 20 6f 6e 6c 79 2e 20 4e 6f 20 73 68 61 72 64 73 only. No shards
5630: 2c 20 6e 6f 20 60 72 65 71 75 69 72 65 60 0a 20 , no `require`.
5640: 20 6f 66 20 61 6e 79 74 68 69 6e 67 20 69 6e 20 of anything in
5650: 60 73 72 63 2f 60 2c 20 61 6e 64 20 6e 6f 74 68 `src/`, and noth
5660: 69 6e 67 20 69 74 20 72 65 61 64 73 20 62 75 74 ing it reads but
5670: 20 77 68 61 74 20 69 74 20 73 61 79 73 2e 0a 0a what it says...
5680: 4b 65 65 70 20 65 61 63 68 20 66 69 6c 65 20 75 Keep each file u
5690: 6e 64 65 72 20 33 30 30 20 6c 69 6e 65 73 2c 20 nder 300 lines,
56a0: 70 6c 61 69 6e 20 61 6e 64 20 63 6f 6d 6d 65 6e plain and commen
56b0: 74 65 64 20 77 68 65 72 65 20 61 20 72 65 61 64 ted where a read
56c0: 65 72 20 77 6f 75 6c 64 0a 61 73 6b 20 77 68 79 er would.ask why
56d0: 2e 20 44 6f 20 6e 6f 74 20 63 68 61 6e 67 65 20 . Do not change
56e0: 61 6e 79 74 68 69 6e 67 20 69 6e 20 60 73 72 63 anything in `src
56f0: 2f 60 2c 20 60 73 70 65 63 2f 60 2c 20 60 74 6f /`, `spec/`, `to
5700: 6f 6c 73 2f 60 20 6f 72 20 60 63 69 2e 63 72 60 ols/` or `ci.cr`
5710: 2e 0a 0a 23 23 20 4c 69 76 65 20 63 6f 6e 73 74 ...## Live const
5720: 61 6e 74 73 0a 0a 54 68 65 73 65 20 61 70 70 6c ants..These appl
5730: 79 20 6f 6e 20 74 68 65 20 68 6f 73 74 20 77 68 y on the host wh
5740: 6f 73 65 20 60 53 79 73 74 65 6d 2e 68 6f 73 74 ose `System.host
5750: 6e 61 6d 65 60 20 69 73 0a 60 69 70 2d 31 37 32 name` is.`ip-172
5760: 2d 33 31 2d 31 37 2d 31 37 37 2e 75 73 2d 77 65 -31-17-177.us-we
5770: 73 74 2d 32 2e 63 6f 6d 70 75 74 65 2e 69 6e 74 st-2.compute.int
5780: 65 72 6e 61 6c 60 2e 0a 0a 2d 20 53 65 72 76 65 ernal`...- Serve
5790: 64 20 72 65 70 6f 73 69 74 6f 72 69 65 73 3a 20 d repositories:
57a0: 60 2f 76 61 72 2f 6c 69 62 2f 66 6f 73 73 69 6c `/var/lib/fossil
57b0: 60 2e 0a 2d 20 54 68 65 20 72 65 63 65 69 70 74 `..- The receipt
57c0: 20 73 65 72 76 69 63 65 27 73 20 73 6f 63 6b 65 service's socke
57d0: 74 3a 20 60 2f 72 75 6e 2f 6f 63 78 2f 72 65 63 t: `/run/ocx/rec
57e0: 65 69 70 74 73 2e 73 6f 63 6b 60 2c 20 69 6e 0a eipts.sock`, in.
57f0: 20 20 60 2f 72 75 6e 2f 6f 63 78 60 2e 0a 2d 20 `/run/ocx`..-
5800: 54 68 65 20 77 65 62 20 72 65 6c 65 61 73 65 20 The web release
5810: 72 6f 6f 74 3a 20 60 2f 76 61 72 2f 6c 69 62 2f root: `/var/lib/
5820: 6f 63 78 2f 72 65 6c 65 61 73 65 32 60 2e 20 54 ocx/release2`. T
5830: 68 65 20 43 47 49 20 72 75 6e 73 0a 20 20 60 63 he CGI runs. `c
5840: 75 72 72 65 6e 74 2f 6f 63 78 32 60 2e 0a 2d 20 urrent/ocx2`..-
5850: 54 68 65 20 64 61 65 6d 6f 6e 27 73 20 72 6f 6f The daemon's roo
5860: 74 3a 20 60 2f 76 61 72 2f 6c 69 62 2f 6f 63 78 t: `/var/lib/ocx
5870: 2f 61 67 65 6e 74 73 2d 64 61 65 6d 6f 6e 60 2e /agents-daemon`.
5880: 20 54 68 65 20 64 61 65 6d 6f 6e 20 69 73 20 73 The daemon is s
5890: 74 61 72 74 65 64 0a 20 20 61 73 20 60 52 4f 4f tarted. as `ROO
58a0: 54 2f 63 75 72 72 65 6e 74 2f 6f 63 78 32 20 64 T/current/ocx2 d
58b0: 61 65 6d 6f 6e 20 52 4f 4f 54 2f 6e 6f 64 65 2f aemon ROOT/node/
58c0: 6e 6f 64 65 73 2e 6a 73 6f 6e 60 2e 0a 2d 20 54 nodes.json`..- T
58d0: 68 65 20 64 61 65 6d 6f 6e 27 73 20 68 6f 6d 65 he daemon's home
58e0: 73 2c 20 62 6f 75 6e 64 20 72 65 61 64 2d 77 72 s, bound read-wr
58f0: 69 74 65 20 61 74 20 74 68 65 20 73 61 6d 65 20 ite at the same
5900: 70 61 74 68 20 77 68 65 6e 20 74 68 65 79 20 65 path when they e
5910: 78 69 73 74 3a 0a 20 20 60 2f 68 6f 6d 65 2f 6f xist:. `/home/o
5920: 63 78 2f 2e 63 6f 64 65 78 60 2c 20 60 2f 68 6f cx/.codex`, `/ho
5930: 6d 65 2f 6f 63 78 2f 2e 63 6c 61 75 64 65 60 2c me/ocx/.claude`,
5940: 20 60 2f 68 6f 6d 65 2f 6f 63 78 2f 2e 63 6c 61 `/home/ocx/.cla
5950: 75 64 65 2e 6a 73 6f 6e 60 2e 20 52 65 61 64 2d ude.json`. Read-
5960: 6f 6e 6c 79 3a 0a 20 20 60 2f 68 6f 6d 65 2f 6f only:. `/home/o
5970: 63 78 2f 2e 6c 6f 63 61 6c 60 2e 20 54 68 65 20 cx/.local`. The
5980: 64 61 65 6d 6f 6e 27 73 20 48 4f 4d 45 20 69 73 daemon's HOME is
5990: 20 60 2f 68 6f 6d 65 2f 6f 63 78 60 2c 20 77 68 `/home/ocx`, wh
59a0: 69 63 68 20 69 73 20 61 20 74 6d 70 66 73 0a 20 ich is a tmpfs.
59b0: 20 77 69 74 68 20 6f 6e 6c 79 20 74 68 6f 73 65 with only those
59c0: 20 70 61 74 68 73 20 62 6f 75 6e 64 20 69 6e 74 paths bound int
59d0: 6f 20 69 74 2e 0a 0a 23 23 20 53 63 72 61 74 63 o it...## Scratc
59e0: 68 20 63 6f 6e 73 74 61 6e 74 73 0a 0a 54 68 65 h constants..The
59f0: 73 65 20 61 70 70 6c 79 20 77 68 65 6e 20 74 68 se apply when th
5a00: 65 20 66 69 72 73 74 20 61 72 67 75 6d 65 6e 74 e first argument
5a10: 20 69 73 20 60 2d 2d 73 63 72 61 74 63 68 20 44 is `--scratch D
5a20: 49 52 60 3b 20 44 49 52 20 69 73 20 61 6e 20 61 IR`; DIR is an a
5a30: 62 73 6f 6c 75 74 65 0a 64 69 72 65 63 74 6f 72 bsolute.director
5a40: 79 2c 20 61 6e 64 20 65 76 65 72 79 20 70 61 74 y, and every pat
5a50: 68 20 69 73 20 74 68 65 6e 20 75 6e 64 65 72 20 h is then under
5a60: 69 74 2e 20 54 68 69 73 20 69 73 20 68 6f 77 20 it. This is how
5a70: 73 70 65 63 73 20 61 6e 64 20 74 68 65 0a 73 63 specs and the.sc
5a80: 72 61 74 63 68 20 64 65 70 6c 6f 79 6d 65 6e 74 ratch deployment
5a90: 20 72 75 6e 20 74 68 65 20 73 61 6d 65 20 63 6f run the same co
5aa0: 64 65 2e 20 54 68 65 20 66 6c 61 67 20 69 73 20 de. The flag is
5ab0: 74 68 65 20 6f 6e 6c 79 20 61 72 67 75 6d 65 6e the only argumen
5ac0: 74 20 74 68 65 0a 6c 61 75 6e 63 68 65 72 20 74 t the.launcher t
5ad0: 61 6b 65 73 20 62 65 73 69 64 65 73 20 69 74 73 akes besides its
5ae0: 20 6d 6f 64 65 2e 0a 0a 2d 20 53 65 72 76 65 64 mode...- Served
5af0: 20 72 65 70 6f 73 69 74 6f 72 69 65 73 3a 20 60 repositories: `
5b00: 44 49 52 2f 66 6f 73 73 69 6c 60 2e 0a 2d 20 53 DIR/fossil`..- S
5b10: 6f 63 6b 65 74 3a 20 60 44 49 52 2f 72 75 6e 2f ocket: `DIR/run/
5b20: 72 65 63 65 69 70 74 73 2e 73 6f 63 6b 60 2c 20 receipts.sock`,
5b30: 69 6e 20 60 44 49 52 2f 72 75 6e 60 2e 0a 2d 20 in `DIR/run`..-
5b40: 57 65 62 20 72 65 6c 65 61 73 65 20 72 6f 6f 74 Web release root
5b50: 3a 20 60 44 49 52 2f 72 65 6c 65 61 73 65 60 2e : `DIR/release`.
5b60: 0a 2d 20 54 68 65 20 64 61 65 6d 6f 6e 27 73 20 .- The daemon's
5b70: 72 6f 6f 74 3a 20 60 44 49 52 2f 64 61 65 6d 6f root: `DIR/daemo
5b80: 6e 60 2e 0a 2d 20 48 6f 6d 65 73 3a 20 60 44 49 n`..- Homes: `DI
5b90: 52 2f 68 6f 6d 65 2f 2e 63 6f 64 65 78 60 20 28 R/home/.codex` (
5ba0: 72 65 61 64 2d 77 72 69 74 65 2c 20 69 66 20 69 read-write, if i
5bb0: 74 20 65 78 69 73 74 73 29 2e 20 48 4f 4d 45 20 t exists). HOME
5bc0: 69 73 20 60 44 49 52 2f 68 6f 6d 65 60 2e 0a 0a is `DIR/home`...
5bd0: 23 23 20 31 2e 20 60 73 63 72 69 70 74 73 2f 72 ## 1. `scripts/r
5be0: 65 63 65 69 70 74 73 2e 63 72 60 3a 20 74 68 65 eceipts.cr`: the
5bf0: 20 72 65 63 65 69 70 74 20 73 65 72 76 69 63 65 receipt service
5c00: 0a 0a 55 73 61 67 65 3a 20 60 72 65 63 65 69 70 ..Usage: `receip
5c10: 74 73 20 53 4f 43 4b 45 54 20 52 45 50 4f 53 49 ts SOCKET REPOSI
5c20: 54 4f 52 49 45 53 60 2e 20 54 77 6f 20 65 78 70 TORIES`. Two exp
5c30: 6c 69 63 69 74 20 61 72 67 75 6d 65 6e 74 73 3a licit arguments:
5c40: 20 74 68 65 20 73 6f 63 6b 65 74 0a 70 61 74 68 the socket.path
5c50: 20 61 6e 64 20 74 68 65 20 64 69 72 65 63 74 6f and the directo
5c60: 72 79 20 6f 66 20 73 65 72 76 65 64 20 72 65 70 ry of served rep
5c70: 6f 73 69 74 6f 72 69 65 73 2e 20 49 74 20 72 75 ositories. It ru
5c80: 6e 73 20 69 6e 73 69 64 65 20 74 68 65 0a 6c 61 ns inside the.la
5c90: 75 6e 63 68 65 72 27 73 20 60 72 65 63 65 69 70 uncher's `receip
5ca0: 74 73 60 20 73 61 6e 64 62 6f 78 20 28 73 65 63 ts` sandbox (sec
5cb0: 74 69 6f 6e 20 32 29 2c 20 77 68 69 63 68 20 70 tion 2), which p
5cc0: 61 73 73 65 73 20 74 68 65 6d 2e 0a 0a 2a 2a 54 asses them...**T
5cd0: 68 65 20 73 6f 63 6b 65 74 2e 2a 2a 20 41 74 20 he socket.** At
5ce0: 73 74 61 72 74 20 69 74 20 72 65 6d 6f 76 65 73 start it removes
5cf0: 20 61 20 73 74 61 6c 65 20 73 6f 63 6b 65 74 20 a stale socket
5d00: 61 74 20 53 4f 43 4b 45 54 2c 20 62 69 6e 64 73 at SOCKET, binds
5d10: 20 61 20 55 6e 69 78 0a 73 74 72 65 61 6d 20 73 a Unix.stream s
5d20: 6f 63 6b 65 74 20 74 68 65 72 65 2c 20 61 6e 64 ocket there, and
5d30: 20 73 65 74 73 20 6d 6f 64 65 20 30 36 30 30 2e sets mode 0600.
5d40: 20 4f 6e 6c 79 20 69 74 73 20 6f 77 6e 20 61 63 Only its own ac
5d50: 63 6f 75 6e 74 20 6d 61 79 20 63 6f 6e 6e 65 63 count may connec
5d60: 74 2c 0a 73 6f 20 63 68 65 63 6b 20 65 76 65 72 t,.so check ever
5d70: 79 20 70 65 65 72 20 77 69 74 68 20 60 67 65 74 y peer with `get
5d80: 73 6f 63 6b 6f 70 74 28 53 4f 5f 50 45 45 52 43 sockopt(SO_PEERC
5d90: 52 45 44 29 60 20 61 6e 64 20 72 65 66 75 73 65 RED)` and refuse
5da0: 20 61 6e 79 20 75 69 64 20 62 75 74 0a 60 4c 69 any uid but.`Li
5db0: 62 43 2e 67 65 74 75 69 64 60 2e 20 57 72 69 74 bC.getuid`. Writ
5dc0: 65 20 74 68 65 20 73 6d 61 6c 6c 20 60 6c 69 62 e the small `lib
5dd0: 60 20 62 69 6e 64 69 6e 67 20 6e 65 65 64 65 64 ` binding needed
5de0: 20 66 6f 72 20 74 68 61 74 20 79 6f 75 72 73 65 for that yourse
5df0: 6c 66 2e 0a 0a 2a 2a 45 61 63 68 20 63 6f 6e 6e lf...**Each conn
5e00: 65 63 74 69 6f 6e 2a 2a 20 69 73 20 73 65 72 76 ection** is serv
5e10: 65 64 20 69 6e 20 69 74 73 20 6f 77 6e 20 66 69 ed in its own fi
5e20: 62 65 72 2c 20 61 74 20 6d 6f 73 74 20 38 20 61 ber, at most 8 a
5e30: 74 20 6f 6e 63 65 2e 20 41 20 6e 69 6e 74 68 0a t once. A ninth.
5e40: 67 65 74 73 20 60 7b 22 75 6e 61 76 61 69 6c 61 gets `{"unavaila
5e50: 62 6c 65 22 3a 20 22 62 75 73 79 22 2c 20 22 72 ble": "busy", "r
5e60: 65 74 72 79 5f 61 66 74 65 72 22 3a 20 31 7d 60 etry_after": 1}`
5e70: 20 61 74 20 6f 6e 63 65 2e 20 45 61 63 68 20 63 at once. Each c
5e80: 6f 6e 6e 65 63 74 69 6f 6e 0a 63 61 72 72 69 65 onnection.carrie
5e90: 73 20 65 78 61 63 74 6c 79 20 74 77 6f 20 6c 69 s exactly two li
5ea0: 6e 65 73 20 6f 66 20 4a 53 4f 4e 2e 20 42 6f 74 nes of JSON. Bot
5eb0: 68 20 6d 75 73 74 20 61 72 72 69 76 65 20 77 69 h must arrive wi
5ec0: 74 68 69 6e 20 32 20 73 65 63 6f 6e 64 73 20 69 thin 2 seconds i
5ed0: 6e 0a 74 6f 74 61 6c 2c 20 6f 72 20 74 68 65 20 n.total, or the
5ee0: 63 6f 6e 6e 65 63 74 69 6f 6e 20 69 73 20 63 6c connection is cl
5ef0: 6f 73 65 64 20 77 69 74 68 0a 60 7b 22 72 65 66 osed with.`{"ref
5f00: 75 73 65 64 22 3a 20 22 72 65 71 75 65 73 74 20 used": "request
5f10: 6e 6f 74 20 72 65 63 65 69 76 65 64 20 77 69 74 not received wit
5f20: 68 69 6e 20 32 20 73 22 7d 60 2e 0a 0a 31 2e 20 hin 2 s"}`...1.
5f30: 2a 2a 54 68 65 20 69 64 65 6e 74 69 74 79 20 6c **The identity l
5f40: 69 6e 65 2c 2a 2a 20 77 72 69 74 74 65 6e 20 62 ine,** written b
5f50: 79 20 74 68 65 20 6c 61 75 6e 63 68 65 72 2c 20 y the launcher,
5f60: 61 74 20 6d 6f 73 74 20 31 20 4b 69 42 3a 0a 20 at most 1 KiB:.
5f70: 20 20 60 7b 22 75 73 65 72 22 3a 20 53 54 52 49 `{"user": STRI
5f80: 4e 47 3f 2c 20 22 63 61 70 61 62 69 6c 69 74 69 NG?, "capabiliti
5f90: 65 73 22 3a 20 53 54 52 49 4e 47 2c 20 22 72 65 es": STRING, "re
5fa0: 70 6f 73 69 74 6f 72 79 22 3a 20 4e 41 4d 45 7d pository": NAME}
5fb0: 60 2e 20 4e 41 4d 45 0a 20 20 20 6d 61 74 63 68 `. NAME. match
5fc0: 65 73 20 60 5c 41 5b 41 2d 5a 61 2d 7a 30 2d 39 es `\A[A-Za-z0-9
5fd0: 5f 5d 5b 41 2d 5a 61 2d 7a 30 2d 39 2e 5f 2d 5d _][A-Za-z0-9._-]
5fe0: 7b 30 2c 39 39 7d 5c 7a 60 20 61 6e 64 20 6d 75 {0,99}\z` and mu
5ff0: 73 74 20 6e 6f 74 20 65 6e 64 20 69 6e 0a 20 20 st not end in.
6000: 20 60 2e 66 6f 73 73 69 6c 60 2e 20 54 68 65 20 `.fossil`. The
6010: 72 65 70 6f 73 69 74 6f 72 79 20 69 73 20 60 52 repository is `R
6020: 45 50 4f 53 49 54 4f 52 49 45 53 2f 4e 41 4d 45 EPOSITORIES/NAME
6030: 2e 66 6f 73 73 69 6c 60 2c 20 77 68 69 63 68 20 .fossil`, which
6040: 6d 75 73 74 0a 20 20 20 65 78 69 73 74 20 61 73 must. exist as
6050: 20 61 20 72 65 67 75 6c 61 72 20 66 69 6c 65 2e a regular file.
6060: 0a 32 2e 20 2a 2a 54 68 65 20 72 65 71 75 65 73 .2. **The reques
6070: 74 20 6c 69 6e 65 2c 2a 2a 20 61 74 20 6d 6f 73 t line,** at mos
6080: 74 20 38 20 4b 69 42 3a 0a 20 20 20 60 7b 22 6f t 8 KiB:. `{"o
6090: 63 78 5f 72 65 63 65 69 70 74 22 3a 20 31 2c 20 cx_receipt": 1,
60a0: 22 61 72 74 69 66 61 63 74 73 22 3a 20 5b 48 41 "artifacts": [HA
60b0: 53 48 2e 2e 2e 5d 3f 2c 20 22 63 61 70 61 62 69 SH...]?, "capabi
60c0: 6c 69 74 69 65 73 5f 6f 66 22 3a 20 55 53 45 52 lities_of": USER
60d0: 3f 7d 60 2e 0a 20 20 20 2d 20 41 6e 79 20 6f 74 ?}`.. - Any ot
60e0: 68 65 72 20 6b 65 79 2c 20 6f 72 20 60 6f 63 78 her key, or `ocx
60f0: 5f 72 65 63 65 69 70 74 60 20 6e 6f 74 20 31 2c _receipt` not 1,
6100: 20 69 73 20 72 65 66 75 73 65 64 2c 20 6e 61 6d is refused, nam
6110: 69 6e 67 20 74 68 65 20 6b 65 79 2e 0a 20 20 20 ing the key..
6120: 2d 20 41 74 20 6d 6f 73 74 20 36 34 20 61 72 74 - At most 64 art
6130: 69 66 61 63 74 73 2e 20 45 61 63 68 20 48 41 53 ifacts. Each HAS
6140: 48 20 6d 61 74 63 68 65 73 20 60 5c 41 28 5b 30 H matches `\A([0
6150: 2d 39 61 2d 66 5d 7b 34 30 7d 7c 5b 30 2d 39 61 -9a-f]{40}|[0-9a
6160: 2d 66 5d 7b 36 34 7d 29 5c 7a 60 2e 0a 20 20 20 -f]{64})\z`..
6170: 2d 20 55 53 45 52 20 69 73 20 61 74 20 6d 6f 73 - USER is at mos
6180: 74 20 31 30 30 20 63 68 61 72 61 63 74 65 72 73 t 100 characters
6190: 2c 20 77 69 74 68 20 6e 6f 20 63 6f 6e 74 72 6f , with no contro
61a0: 6c 20 63 68 61 72 61 63 74 65 72 73 2e 0a 0a 54 l characters...T
61b0: 68 65 20 61 6e 73 77 65 72 20 69 73 20 6f 6e 65 he answer is one
61c0: 20 6c 69 6e 65 20 6f 66 20 4a 53 4f 4e 2c 20 74 line of JSON, t
61d0: 68 65 6e 20 74 68 65 20 63 6f 6e 6e 65 63 74 69 hen the connecti
61e0: 6f 6e 20 63 6c 6f 73 65 73 2e 20 49 74 20 69 73 on closes. It is
61f0: 20 6f 6e 65 20 6f 66 3a 0a 2d 20 60 7b 22 61 72 one of:.- `{"ar
6200: 74 69 66 61 63 74 73 22 3a 20 5b 2e 2e 2e 5d 2c tifacts": [...],
6210: 20 22 75 73 65 72 22 3a 20 7b 2e 2e 2e 7d 3f 7d "user": {...}?}
6220: 60 3b 0a 2d 20 60 7b 22 72 65 66 75 73 65 64 22 `;.- `{"refused"
6230: 3a 20 52 45 41 53 4f 4e 7d 60 20 66 6f 72 20 61 : REASON}` for a
6240: 20 62 61 64 20 72 65 71 75 65 73 74 3b 0a 2d 20 bad request;.-
6250: 60 7b 22 75 6e 61 76 61 69 6c 61 62 6c 65 22 3a `{"unavailable":
6260: 20 52 45 41 53 4f 4e 2c 20 22 72 65 74 72 79 5f REASON, "retry_
6270: 61 66 74 65 72 22 3a 20 31 7d 60 20 77 68 65 6e after": 1}` when
6280: 20 74 68 65 20 64 61 74 61 62 61 73 65 20 63 61 the database ca
6290: 6e 6e 6f 74 20 62 65 0a 20 20 72 65 61 64 20 6e nnot be. read n
62a0: 6f 77 2e 0a 0a 4e 6f 20 61 6e 73 77 65 72 20 69 ow...No answer i
62b0: 73 20 70 61 72 74 69 61 6c 2e 0a 0a 2a 2a 41 75 s partial...**Au
62c0: 74 68 6f 72 69 7a 61 74 69 6f 6e 2a 2a 2c 20 66 thorization**, f
62d0: 72 6f 6d 20 74 68 65 20 69 64 65 6e 74 69 74 79 rom the identity
62e0: 20 6c 69 6e 65 27 73 20 60 63 61 70 61 62 69 6c line's `capabil
62f0: 69 74 69 65 73 60 3a 0a 2d 20 41 20 63 61 6c 6c ities`:.- A call
6300: 65 72 20 77 69 74 68 6f 75 74 20 60 6f 60 20 28 er without `o` (
6310: 52 65 61 64 29 20 67 65 74 73 20 65 76 65 72 79 Read) gets every
6320: 20 61 72 74 69 66 61 63 74 20 61 73 0a 20 20 60 artifact as. `
6330: 7b 22 61 72 74 69 66 61 63 74 22 3a 20 48 2c 20 {"artifact": H,
6340: 22 72 65 63 65 69 76 65 64 22 3a 20 66 61 6c 73 "received": fals
6350: 65 7d 60 2c 20 61 6e 64 20 60 75 73 65 72 60 20 e}`, and `user`
6360: 61 73 0a 20 20 60 7b 22 75 73 65 72 22 3a 20 55 as. `{"user": U
6370: 2c 20 22 63 61 70 61 62 69 6c 69 74 69 65 73 22 , "capabilities"
6380: 3a 20 6e 75 6c 6c 7d 60 2c 20 77 69 74 68 20 6e : null}`, with n
6390: 6f 20 64 61 74 61 62 61 73 65 20 72 65 61 64 20 o database read
63a0: 61 74 20 61 6c 6c 2e 0a 2d 20 41 20 70 72 69 76 at all..- A priv
63b0: 61 74 65 20 61 72 74 69 66 61 63 74 20 28 61 20 ate artifact (a
63c0: 72 6f 77 20 69 6e 20 60 70 72 69 76 61 74 65 60 row in `private`
63d0: 20 66 6f 72 20 69 74 73 20 72 69 64 29 20 63 6f for its rid) co
63e0: 75 6e 74 73 20 61 73 20 72 65 63 65 69 76 65 64 unts as received
63f0: 0a 20 20 6f 6e 6c 79 20 66 6f 72 20 61 20 63 61 . only for a ca
6400: 6c 6c 65 72 20 68 6f 6c 64 69 6e 67 20 60 78 60 ller holding `x`
6410: 2e 20 4f 74 68 65 72 77 69 73 65 20 69 74 20 69 . Otherwise it i
6420: 73 0a 20 20 60 7b 22 61 72 74 69 66 61 63 74 22 s. `{"artifact"
6430: 3a 20 48 2c 20 22 72 65 63 65 69 76 65 64 22 3a : H, "received":
6440: 20 66 61 6c 73 65 7d 60 2e 0a 0a 2a 2a 52 65 61 false}`...**Rea
6450: 64 69 6e 67 20 74 68 65 20 64 61 74 61 62 61 73 ding the databas
6460: 65 2e 2a 2a 20 57 72 69 74 65 20 79 6f 75 72 20 e.** Write your
6470: 6f 77 6e 20 60 6c 69 62 20 4c 69 62 53 51 4c 69 own `lib LibSQLi
6480: 74 65 33 60 20 62 69 6e 64 69 6e 67 2c 20 6c 69 te3` binding, li
6490: 6e 6b 65 64 0a 77 69 74 68 20 60 40 5b 4c 69 6e nked.with `@[Lin
64a0: 6b 28 22 73 71 6c 69 74 65 33 22 29 5d 60 2c 20 k("sqlite3")]`,
64b0: 77 69 74 68 20 6f 6e 6c 79 20 74 68 65 20 66 75 with only the fu
64c0: 6e 63 74 69 6f 6e 73 20 79 6f 75 20 75 73 65 3a nctions you use:
64d0: 20 60 6f 70 65 6e 5f 76 32 60 2c 0a 60 63 6c 6f `open_v2`,.`clo
64e0: 73 65 5f 76 32 60 2c 20 60 70 72 65 70 61 72 65 se_v2`, `prepare
64f0: 5f 76 32 60 2c 20 60 62 69 6e 64 5f 74 65 78 74 _v2`, `bind_text
6500: 60 2c 20 60 73 74 65 70 60 2c 20 60 63 6f 6c 75 `, `step`, `colu
6510: 6d 6e 5f 69 6e 74 36 34 60 2c 0a 60 63 6f 6c 75 mn_int64`,.`colu
6520: 6d 6e 5f 74 65 78 74 60 2c 20 60 63 6f 6c 75 6d mn_text`, `colum
6530: 6e 5f 74 79 70 65 60 2c 20 60 66 69 6e 61 6c 69 n_type`, `finali
6540: 7a 65 60 2c 20 60 65 78 65 63 60 2c 20 60 62 75 ze`, `exec`, `bu
6550: 73 79 5f 74 69 6d 65 6f 75 74 60 2c 0a 60 65 78 sy_timeout`,.`ex
6560: 74 65 6e 64 65 64 5f 65 72 72 63 6f 64 65 60 20 tended_errcode`
6570: 61 6e 64 20 60 65 72 72 6d 73 67 60 2e 0a 0a 46 and `errmsg`...F
6580: 6f 72 20 65 61 63 68 20 72 65 71 75 65 73 74 3a or each request:
6590: 0a 2d 20 4f 70 65 6e 20 74 68 65 20 66 69 6c 65 .- Open the file
65a0: 20 77 69 74 68 20 60 73 71 6c 69 74 65 33 5f 6f with `sqlite3_o
65b0: 70 65 6e 5f 76 32 28 22 66 69 6c 65 3a 22 20 2b pen_v2("file:" +
65c0: 20 70 65 72 63 65 6e 74 2d 65 6e 63 6f 64 65 64 percent-encoded
65d0: 20 70 61 74 68 20 2b 0a 20 20 22 3f 6d 6f 64 65 path +. "?mode
65e0: 3d 72 6f 22 2c 20 64 62 2c 20 53 51 4c 49 54 45 =ro", db, SQLITE
65f0: 5f 4f 50 45 4e 5f 52 45 41 44 4f 4e 4c 59 20 7c _OPEN_READONLY |
6600: 20 53 51 4c 49 54 45 5f 4f 50 45 4e 5f 55 52 49 SQLITE_OPEN_URI
6610: 2c 20 6e 69 6c 29 60 2e 20 4e 65 76 65 72 0a 20 , nil)`. Never.
6620: 20 60 69 6d 6d 75 74 61 62 6c 65 60 20 6f 72 20 `immutable` or
6630: 60 6e 6f 6c 6f 63 6b 60 2e 0a 2d 20 52 75 6e 20 `nolock`..- Run
6640: 60 50 52 41 47 4d 41 20 71 75 65 72 79 5f 6f 6e `PRAGMA query_on
6650: 6c 79 3d 31 60 2c 20 74 68 65 6e 20 60 73 71 6c ly=1`, then `sql
6660: 69 74 65 33 5f 62 75 73 79 5f 74 69 6d 65 6f 75 ite3_busy_timeou
6670: 74 28 64 62 2c 20 32 30 30 30 29 60 2e 0a 2d 20 t(db, 2000)`..-
6680: 52 65 61 64 20 65 76 65 72 79 74 68 69 6e 67 20 Read everything
6690: 69 6e 20 6f 6e 65 20 60 42 45 47 49 4e 60 20 2e in one `BEGIN` .
66a0: 2e 2e 20 60 43 4f 4d 4d 49 54 60 2c 20 74 68 65 .. `COMMIT`, the
66b0: 6e 20 63 6c 6f 73 65 2e 0a 0a 50 72 65 70 61 72 n close...Prepar
66c0: 65 64 20 73 74 61 74 65 6d 65 6e 74 73 2c 20 66 ed statements, f
66d0: 69 78 65 64 2c 20 70 61 72 61 6d 65 74 65 72 69 ixed, parameteri
66e0: 7a 65 64 20 6f 6e 6c 79 20 62 79 20 62 6f 75 6e zed only by boun
66f0: 64 20 74 65 78 74 3a 0a 2d 20 60 53 45 4c 45 43 d text:.- `SELEC
6700: 54 20 62 2e 72 69 64 2c 20 62 2e 72 63 76 69 64 T b.rid, b.rcvid
6710: 2c 20 45 58 49 53 54 53 28 53 45 4c 45 43 54 20 , EXISTS(SELECT
6720: 31 20 46 52 4f 4d 20 70 72 69 76 61 74 65 20 70 1 FROM private p
6730: 20 57 48 45 52 45 20 70 2e 72 69 64 3d 62 2e 72 WHERE p.rid=b.r
6740: 69 64 29 2c 20 75 2e 6c 6f 67 69 6e 2c 20 75 2e id), u.login, u.
6750: 63 61 70 20 46 52 4f 4d 20 62 6c 6f 62 20 62 20 cap FROM blob b
6760: 4c 45 46 54 20 4a 4f 49 4e 20 72 63 76 66 72 6f LEFT JOIN rcvfro
6770: 6d 20 72 20 4f 4e 20 72 2e 72 63 76 69 64 3d 62 m r ON r.rcvid=b
6780: 2e 72 63 76 69 64 20 4c 45 46 54 20 4a 4f 49 4e .rcvid LEFT JOIN
6790: 20 75 73 65 72 20 75 20 4f 4e 20 75 2e 75 69 64 user u ON u.uid
67a0: 3d 72 2e 75 69 64 20 57 48 45 52 45 20 62 2e 75 =r.uid WHERE b.u
67b0: 75 69 64 3d 3f 31 20 41 4e 44 20 62 2e 73 69 7a uid=?1 AND b.siz
67c0: 65 3e 3d 30 60 0a 2d 20 60 53 45 4c 45 43 54 20 e>=0`.- `SELECT
67d0: 63 61 70 20 46 52 4f 4d 20 75 73 65 72 20 57 48 cap FROM user WH
67e0: 45 52 45 20 6c 6f 67 69 6e 3d 3f 31 60 0a 2d 20 ERE login=?1`.-
67f0: 60 53 45 4c 45 43 54 20 6c 6f 67 69 6e 2c 20 63 `SELECT login, c
6800: 61 70 20 46 52 4f 4d 20 75 73 65 72 20 57 48 45 ap FROM user WHE
6810: 52 45 20 6c 6f 67 69 6e 20 49 4e 20 28 27 6e 6f RE login IN ('no
6820: 62 6f 64 79 27 2c 27 61 6e 6f 6e 79 6d 6f 75 73 body','anonymous
6830: 27 2c 27 72 65 61 64 65 72 27 2c 27 64 65 76 65 ','reader','deve
6840: 6c 6f 70 65 72 27 29 60 0a 2d 20 60 53 45 4c 45 loper')`.- `SELE
6850: 43 54 20 76 61 6c 75 65 20 46 52 4f 4d 20 63 6f CT value FROM co
6860: 6e 66 69 67 20 57 48 45 52 45 20 6e 61 6d 65 3d nfig WHERE name=
6870: 3f 31 60 2c 20 62 6f 75 6e 64 20 6f 6e 6c 79 20 ?1`, bound only
6880: 74 6f 20 60 6d 6f 64 72 65 71 2d 77 69 6b 69 60 to `modreq-wiki`
6890: 20 6f 72 0a 20 20 60 6d 6f 64 72 65 71 2d 74 6b or. `modreq-tk
68a0: 74 60 2e 0a 0a 2a 2a 45 72 72 6f 72 73 2e 2a 2a t`...**Errors.**
68b0: 20 53 51 4c 49 54 45 5f 42 55 53 59 2c 20 53 51 SQLITE_BUSY, SQ
68c0: 4c 49 54 45 5f 4c 4f 43 4b 45 44 20 61 6e 64 20 LITE_LOCKED and
68d0: 61 6e 79 20 53 51 4c 49 54 45 5f 52 45 41 44 4f any SQLITE_READO
68e0: 4e 4c 59 5f 2a 20 28 73 75 63 68 20 61 73 0a 52 NLY_* (such as.R
68f0: 45 41 44 4f 4e 4c 59 5f 52 4f 4c 4c 42 41 43 4b EADONLY_ROLLBACK
6900: 20 66 6f 72 20 61 20 68 6f 74 20 6a 6f 75 72 6e for a hot journ
6910: 61 6c 2c 20 6f 72 20 52 45 41 44 4f 4e 4c 59 5f al, or READONLY_
6920: 43 41 4e 54 49 4e 49 54 29 20 67 69 76 65 0a 60 CANTINIT) give.`
6930: 7b 22 75 6e 61 76 61 69 6c 61 62 6c 65 22 3a 20 {"unavailable":
6940: 2e 2e 2e 7d 60 2e 20 53 6f 20 64 6f 20 53 51 4c ...}`. So do SQL
6950: 49 54 45 5f 43 41 4e 54 4f 50 45 4e 20 61 6e 64 ITE_CANTOPEN and
6960: 20 61 6e 79 20 6f 74 68 65 72 20 65 72 72 6f 72 any other error
6970: 2e 20 54 68 65 0a 72 65 61 73 6f 6e 20 69 73 20 . The.reason is
6980: 74 68 65 20 53 51 4c 69 74 65 20 65 72 72 6f 72 the SQLite error
6990: 20 6e 61 6d 65 20 61 6e 64 20 6d 65 73 73 61 67 name and messag
69a0: 65 2c 20 6e 65 76 65 72 20 61 20 70 61 74 68 20 e, never a path
69b0: 66 72 6f 6d 20 61 20 72 65 71 75 65 73 74 0a 28 from a request.(
69c0: 74 68 65 72 65 20 69 73 20 6e 6f 6e 65 29 2e 0a there is none)..
69d0: 0a 2a 2a 43 61 70 61 62 69 6c 69 74 69 65 73 2e .**Capabilities.
69e0: 2a 2a 20 54 68 65 73 65 20 63 6f 70 79 20 46 6f ** These copy Fo
69f0: 73 73 69 6c 20 32 2e 32 37 27 73 20 60 63 61 70 ssil 2.27's `cap
6a00: 61 62 69 6c 69 74 79 5f 65 78 70 61 6e 64 60 20 ability_expand`
6a10: 61 6e 64 0a 60 63 61 70 61 62 69 6c 69 74 79 5f and.`capability_
6a20: 73 74 72 69 6e 67 60 2e 20 54 68 65 20 72 65 73 string`. The res
6a30: 75 6c 74 20 6d 75 73 74 20 65 71 75 61 6c 20 46 ult must equal F
6a40: 6f 73 73 69 6c 27 73 20 6f 77 6e 0a 60 53 45 4c ossil's own.`SEL
6a50: 45 43 54 20 66 75 6c 6c 63 61 70 28 63 61 70 29 ECT fullcap(cap)
6a60: 60 2e 0a 2d 20 53 74 61 72 74 20 66 72 6f 6d 20 `..- Start from
6a70: 74 68 65 20 75 73 65 72 27 73 20 60 63 61 70 60 the user's `cap`
6a80: 2c 20 6b 65 65 70 69 6e 67 20 6f 6e 6c 79 20 63 , keeping only c
6a90: 68 61 72 61 63 74 65 72 73 20 60 27 30 27 2e 2e haracters `'0'..
6aa0: 27 7a 27 60 2e 0a 2d 20 41 64 64 20 61 6e 6f 6e 'z'`..- Add anon
6ab0: 79 6d 6f 75 73 27 73 20 61 6e 64 20 6e 6f 62 6f ymous's and nobo
6ac0: 64 79 27 73 20 63 61 70 73 2e 0a 2d 20 49 66 20 dy's caps..- If
6ad0: 74 68 65 20 73 65 74 20 68 61 73 20 60 61 60 20 the set has `a`
6ae0: 6f 72 20 60 73 60 2c 20 61 64 64 20 60 62 63 64 or `s`, add `bcd
6af0: 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 74 77 efghijklmnopqrtw
6b00: 7a 32 33 34 35 36 37 41 44 60 2e 0a 2d 20 49 66 z234567AD`..- If
6b10: 20 69 74 20 68 61 73 20 60 76 60 2c 20 61 64 64 it has `v`, add
6b20: 20 64 65 76 65 6c 6f 70 65 72 27 73 20 63 61 70 developer's cap
6b30: 73 2e 0a 2d 20 49 66 20 69 74 20 68 61 73 20 60 s..- If it has `
6b40: 75 60 2c 20 61 64 64 20 72 65 61 64 65 72 27 73 u`, add reader's
6b50: 20 63 61 70 73 2c 20 74 68 65 6e 20 64 65 76 65 caps, then deve
6b60: 6c 6f 70 65 72 27 73 20 63 61 70 73 20 69 66 20 loper's caps if
6b70: 60 76 60 20 69 73 20 6e 6f 77 0a 20 20 70 72 65 `v` is now. pre
6b80: 73 65 6e 74 20 61 6e 64 20 74 68 65 79 20 77 65 sent and they we
6b90: 72 65 20 6e 6f 74 20 61 64 64 65 64 20 62 65 66 re not added bef
6ba0: 6f 72 65 2e 0a 2d 20 52 65 6e 64 65 72 20 69 6e ore..- Render in
6bb0: 20 6f 72 64 65 72 3a 20 60 61 60 2e 2e 60 7a 60 order: `a`..`z`
6bc0: 2c 20 74 68 65 6e 20 60 30 60 2e 2e 60 39 60 2c , then `0`..`9`,
6bd0: 20 74 68 65 6e 20 60 41 60 2e 2e 60 5a 60 2e 20 then `A`..`Z`.
6be0: 41 6e 79 20 6f 74 68 65 72 0a 20 20 63 68 61 72 Any other. char
6bf0: 61 63 74 65 72 20 69 6e 20 72 61 6e 67 65 20 69 acter in range i
6c00: 73 20 64 72 6f 70 70 65 64 2e 0a 0a 2a 2a 54 68 s dropped...**Th
6c10: 65 20 61 6e 73 77 65 72 27 73 20 66 69 65 6c 64 e answer's field
6c20: 73 2e 2a 2a 0a 2d 20 46 6f 72 20 65 61 63 68 20 s.**.- For each
6c30: 61 72 74 69 66 61 63 74 2c 20 69 6e 20 74 68 65 artifact, in the
6c40: 20 6f 72 64 65 72 20 61 73 6b 65 64 3a 0a 20 20 order asked:.
6c50: 60 7b 22 61 72 74 69 66 61 63 74 22 3a 20 48 2c `{"artifact": H,
6c60: 20 22 72 65 63 65 69 76 65 64 22 3a 20 74 72 75 "received": tru
6c70: 65 2c 20 22 73 65 6e 64 65 72 22 3a 20 4c 4f 47 e, "sender": LOG
6c80: 49 4e 3f 2c 20 22 63 61 70 61 62 69 6c 69 74 69 IN?, "capabiliti
6c90: 65 73 22 3a 20 45 58 50 41 4e 44 45 44 3f 2c 20 es": EXPANDED?,
6ca0: 22 72 65 63 65 69 70 74 22 3a 20 52 43 56 49 44 "receipt": RCVID
6cb0: 2c 20 22 72 69 64 22 3a 20 52 49 44 7d 60 2c 0a , "rid": RID}`,.
6cc0: 20 20 6f 72 20 60 7b 22 61 72 74 69 66 61 63 74 or `{"artifact
6cd0: 22 3a 20 48 2c 20 22 72 65 63 65 69 76 65 64 22 ": H, "received"
6ce0: 3a 20 66 61 6c 73 65 7d 60 2e 20 60 73 65 6e 64 : false}`. `send
6cf0: 65 72 60 20 61 6e 64 20 60 63 61 70 61 62 69 6c er` and `capabil
6d00: 69 74 69 65 73 60 0a 20 20 61 72 65 20 61 62 73 ities`. are abs
6d10: 65 6e 74 20 77 68 65 6e 20 74 68 65 20 72 65 63 ent when the rec
6d20: 65 69 70 74 20 68 61 73 20 6e 6f 20 75 73 65 72 eipt has no user
6d30: 2e 0a 2d 20 46 6f 72 20 60 63 61 70 61 62 69 6c ..- For `capabil
6d40: 69 74 69 65 73 5f 6f 66 60 3a 0a 20 20 60 7b 22 ities_of`:. `{"
6d50: 75 73 65 72 22 3a 20 55 2c 20 22 63 61 70 61 62 user": U, "capab
6d60: 69 6c 69 74 69 65 73 22 3a 20 45 58 50 41 4e 44 ilities": EXPAND
6d70: 45 44 20 6f 72 20 6e 75 6c 6c 2c 20 22 77 69 6b ED or null, "wik
6d80: 69 5f 6d 6f 64 65 72 61 74 65 64 22 3a 20 42 4f i_moderated": BO
6d90: 4f 4c 3f 2c 20 22 74 69 63 6b 65 74 5f 6d 6f 64 OL?, "ticket_mod
6da0: 65 72 61 74 65 64 22 3a 20 42 4f 4f 4c 3f 7d 60 erated": BOOL?}`
6db0: 2e 0a 20 20 2d 20 60 63 61 70 61 62 69 6c 69 74 .. - `capabilit
6dc0: 69 65 73 60 20 69 73 20 6e 75 6c 6c 20 77 68 65 ies` is null whe
6dd0: 6e 20 74 68 65 72 65 20 69 73 20 6e 6f 20 73 75 n there is no su
6de0: 63 68 20 75 73 65 72 2e 0a 20 20 2d 20 60 77 69 ch user.. - `wi
6df0: 6b 69 5f 6d 6f 64 65 72 61 74 65 64 60 20 69 73 ki_moderated` is
6e00: 20 74 72 75 65 20 77 68 65 6e 20 60 6d 6f 64 72 true when `modr
6e10: 65 71 2d 77 69 6b 69 60 20 69 73 20 74 72 75 65 eq-wiki` is true
6e20: 20 62 79 20 46 6f 73 73 69 6c 27 73 0a 20 20 20 by Fossil's.
6e30: 20 60 69 73 5f 74 72 75 74 68 60 20 28 22 6f 6e `is_truth` ("on
6e40: 22 2c 20 22 79 65 73 22 2c 20 22 74 72 75 65 22 ", "yes", "true"
6e50: 2c 20 22 31 22 2c 20 63 61 73 65 2d 69 6e 73 65 , "1", case-inse
6e60: 6e 73 69 74 69 76 65 29 20 61 6e 64 20 74 68 65 nsitive) and the
6e70: 20 75 73 65 72 27 73 0a 20 20 20 20 65 78 70 61 user's. expa
6e80: 6e 64 65 64 20 63 61 70 73 20 6c 61 63 6b 20 60 nded caps lack `
6e90: 6c 60 2e 0a 20 20 2d 20 60 74 69 63 6b 65 74 5f l`.. - `ticket_
6ea0: 6d 6f 64 65 72 61 74 65 64 60 20 69 73 20 74 68 moderated` is th
6eb0: 65 20 73 61 6d 65 20 66 6f 72 20 60 6d 6f 64 72 e same for `modr
6ec0: 65 71 2d 74 6b 74 60 20 61 6e 64 20 60 71 60 2e eq-tkt` and `q`.
6ed0: 0a 20 20 2d 20 42 6f 74 68 20 61 72 65 20 61 62 . - Both are ab
6ee0: 73 65 6e 74 20 77 68 65 6e 20 60 63 61 70 61 62 sent when `capab
6ef0: 69 6c 69 74 69 65 73 60 20 69 73 20 6e 75 6c 6c ilities` is null
6f00: 2e 0a 0a 4e 65 76 65 72 20 72 65 61 64 20 6f 72 ...Never read or
6f10: 20 72 65 74 75 72 6e 20 61 6e 79 20 6f 74 68 65 return any othe
6f20: 72 20 63 6f 6c 75 6d 6e 2e 20 54 68 65 20 61 6e r column. The an
6f30: 73 77 65 72 20 74 79 70 65 73 20 68 61 76 65 20 swer types have
6f40: 6e 6f 20 66 69 65 6c 64 20 66 6f 72 0a 70 77 2c no field for.pw,
6f50: 20 63 6f 6f 6b 69 65 2c 20 69 70 61 64 64 72 20 cookie, ipaddr
6f60: 6f 72 20 6e 6f 6e 63 65 2e 0a 0a 4c 6f 67 20 6f or nonce...Log o
6f70: 6e 65 20 6c 69 6e 65 20 70 65 72 20 63 6f 6e 6e ne line per conn
6f80: 65 63 74 69 6f 6e 20 74 6f 20 73 74 61 6e 64 61 ection to standa
6f90: 72 64 20 65 72 72 6f 72 3a 20 55 54 43 20 74 69 rd error: UTC ti
6fa0: 6d 65 2c 20 72 65 70 6f 73 69 74 6f 72 79 2c 0a me, repository,.
6fb0: 63 6f 75 6e 74 20 61 73 6b 65 64 2c 20 6f 75 74 count asked, out
6fc0: 63 6f 6d 65 2c 20 6d 69 6c 6c 69 73 65 63 6f 6e come, millisecon
6fd0: 64 73 2e 20 4e 6f 20 68 61 73 68 65 73 20 6f 72 ds. No hashes or
6fe0: 20 75 73 65 72 20 6e 61 6d 65 73 2e 0a 0a 23 23 user names...##
6ff0: 20 32 2e 20 60 73 63 72 69 70 74 73 2f 73 74 61 2. `scripts/sta
7000: 72 74 2d 6f 63 78 2e 63 72 60 3a 20 74 68 65 20 rt-ocx.cr`: the
7010: 6c 61 75 6e 63 68 65 72 0a 0a 49 74 20 68 61 73 launcher..It has
7020: 20 74 68 72 65 65 20 6d 6f 64 65 73 2e 20 45 61 three modes. Ea
7030: 63 68 20 65 6e 64 73 20 62 79 20 60 65 78 65 63 ch ends by `exec
7040: 60 69 6e 67 20 60 2f 75 73 72 2f 62 69 6e 2f 62 `ing `/usr/bin/b
7050: 77 72 61 70 60 20 77 69 74 68 20 61 20 66 69 78 wrap` with a fix
7060: 65 64 0a 61 72 67 75 6d 65 6e 74 20 6c 69 73 74 ed.argument list
7070: 20 62 75 69 6c 74 20 62 79 20 61 20 70 75 72 65 built by a pure
7080: 20 66 75 6e 63 74 69 6f 6e 20 70 65 72 20 6d 6f function per mo
7090: 64 65 2c 20 73 6f 20 69 74 20 63 61 6e 20 62 65 de, so it can be
70a0: 20 70 72 69 6e 74 65 64 20 61 6e 64 0a 74 65 73 printed and.tes
70b0: 74 65 64 2e 20 49 66 20 6e 6f 20 6d 6f 64 65 20 ted. If no mode
70c0: 69 73 20 72 65 63 6f 67 6e 69 73 65 64 2c 20 70 is recognised, p
70d0: 72 69 6e 74 20 61 20 75 73 61 67 65 20 6c 69 6e rint a usage lin
70e0: 65 20 61 6e 64 20 65 78 69 74 20 32 2e 0a 0a 2a e and exit 2...*
70f0: 2a 28 61 29 20 60 6f 63 78 32 2d 63 67 69 60 2c *(a) `ocx2-cgi`,
7100: 2a 2a 20 77 68 65 6e 20 74 68 65 20 70 72 6f 67 ** when the prog
7110: 72 61 6d 27 73 20 62 61 73 65 6e 61 6d 65 20 28 ram's basename (
7120: 61 72 67 76 5b 30 5d 29 20 69 73 20 60 6f 63 78 argv[0]) is `ocx
7130: 32 2d 63 67 69 60 2e 0a 46 6f 73 73 69 6c 20 72 2-cgi`..Fossil r
7140: 75 6e 73 20 69 74 20 61 73 20 61 6e 20 2f 65 78 uns it as an /ex
7150: 74 20 70 72 6f 67 72 61 6d 2c 20 77 69 74 68 20 t program, with
7160: 6e 6f 20 61 72 67 75 6d 65 6e 74 73 2c 20 69 6e no arguments, in
7170: 20 61 20 63 6c 65 61 72 65 64 0a 65 6e 76 69 72 a cleared.envir
7180: 6f 6e 6d 65 6e 74 2e 0a 2d 20 2a 2a 50 69 6e 20 onment..- **Pin
7190: 74 68 65 20 72 65 6c 65 61 73 65 3a 2a 2a 20 60 the release:** `
71a0: 46 69 6c 65 2e 72 65 61 6c 70 61 74 68 28 52 45 File.realpath(RE
71b0: 4c 45 41 53 45 5f 52 4f 4f 54 2f 63 75 72 72 65 LEASE_ROOT/curre
71c0: 6e 74 29 60 20 67 69 76 65 73 20 74 68 65 0a 20 nt)` gives the.
71d0: 20 72 65 6c 65 61 73 65 20 64 69 72 65 63 74 6f release directo
71e0: 72 79 2c 20 61 6e 64 20 69 74 73 20 60 6f 63 78 ry, and its `ocx
71f0: 32 60 20 69 73 20 74 68 65 20 70 72 6f 67 72 61 2` is the progra
7200: 6d 2e 0a 2d 20 2a 2a 43 6c 6f 73 65 20 69 6e 68 m..- **Close inh
7210: 65 72 69 74 65 64 20 64 65 73 63 72 69 70 74 6f erited descripto
7220: 72 73 2a 2a 20 61 62 6f 76 65 20 32 2e 20 57 61 rs** above 2. Wa
7230: 6c 6b 20 60 2f 70 72 6f 63 2f 73 65 6c 66 2f 66 lk `/proc/self/f
7240: 64 60 2c 20 73 6b 69 70 70 69 6e 67 0a 20 20 74 d`, skipping. t
7250: 68 65 20 64 69 72 65 63 74 6f 72 79 27 73 20 6f he directory's o
7260: 77 6e 20 64 65 73 63 72 69 70 74 6f 72 2e 0a 2d wn descriptor..-
7270: 20 2a 2a 49 66 20 60 50 41 54 48 5f 49 4e 46 4f **If `PATH_INFO
7280: 60 20 69 73 20 65 78 61 63 74 6c 79 20 60 2f 72 ` is exactly `/r
7290: 65 63 65 69 70 74 60 3a 2a 2a 0a 20 20 2d 20 43 eceipt`:**. - C
72a0: 6f 6e 6e 65 63 74 20 74 6f 20 74 68 65 20 72 65 onnect to the re
72b0: 63 65 69 70 74 20 73 6f 63 6b 65 74 2e 0a 20 20 ceipt socket..
72c0: 2d 20 57 72 69 74 65 20 74 68 65 20 69 64 65 6e - Write the iden
72d0: 74 69 74 79 20 6c 69 6e 65 3a 0a 20 20 20 20 2d tity line:. -
72e0: 20 60 75 73 65 72 60 20 69 73 20 60 46 4f 53 53 `user` is `FOSS
72f0: 49 4c 5f 55 53 45 52 60 2c 20 61 62 73 65 6e 74 IL_USER`, absent
7300: 20 77 68 65 6e 20 75 6e 73 65 74 3b 0a 20 20 20 when unset;.
7310: 20 2d 20 60 63 61 70 61 62 69 6c 69 74 69 65 73 - `capabilities
7320: 60 20 69 73 20 60 46 4f 53 53 49 4c 5f 43 41 50 ` is `FOSSIL_CAP
7330: 41 42 49 4c 49 54 49 45 53 60 20 6f 72 20 22 22 ABILITIES` or ""
7340: 3b 0a 20 20 20 20 2d 20 60 72 65 70 6f 73 69 74 ;. - `reposit
7350: 6f 72 79 60 20 69 73 20 60 46 69 6c 65 2e 62 61 ory` is `File.ba
7360: 73 65 6e 61 6d 65 28 46 4f 53 53 49 4c 5f 52 45 sename(FOSSIL_RE
7370: 50 4f 53 49 54 4f 52 59 2c 20 22 2e 66 6f 73 73 POSITORY, ".foss
7380: 69 6c 22 29 60 2e 0a 20 20 2d 20 4d 61 6b 65 20 il")`.. - Make
7390: 74 68 61 74 20 63 6f 6e 6e 65 63 74 69 6f 6e 20 that connection
73a0: 64 65 73 63 72 69 70 74 6f 72 20 33 2c 20 77 69 descriptor 3, wi
73b0: 74 68 6f 75 74 20 63 6c 6f 73 65 2d 6f 6e 2d 65 thout close-on-e
73c0: 78 65 63 2e 0a 20 20 2d 20 45 78 65 63 20 62 77 xec.. - Exec bw
73d0: 72 61 70 20 77 69 74 68 3a 0a 20 20 20 20 2d 20 rap with:. -
73e0: 60 2d 2d 75 6e 73 68 61 72 65 2d 61 6c 6c 20 2d `--unshare-all -
73f0: 2d 64 69 65 2d 77 69 74 68 2d 70 61 72 65 6e 74 -die-with-parent
7400: 20 2d 2d 6e 65 77 2d 73 65 73 73 69 6f 6e 20 2d --new-session -
7410: 2d 63 6c 65 61 72 65 6e 76 60 3b 0a 20 20 20 20 -clearenv`;.
7420: 2d 20 60 2d 2d 72 6f 2d 62 69 6e 64 20 2f 75 73 - `--ro-bind /us
7430: 72 20 2f 75 73 72 60 2c 20 70 6c 75 73 20 60 2d r /usr`, plus `-
7440: 2d 72 6f 2d 62 69 6e 64 2d 74 72 79 60 20 66 6f -ro-bind-try` fo
7450: 72 20 60 2f 6c 69 62 60 2c 20 60 2f 6c 69 62 36 r `/lib`, `/lib6
7460: 34 60 0a 20 20 20 20 20 20 61 6e 64 20 60 2f 62 4`. and `/b
7470: 69 6e 60 3b 0a 20 20 20 20 2d 20 60 2d 2d 70 72 in`;. - `--pr
7480: 6f 63 20 2f 70 72 6f 63 20 2d 2d 64 65 76 20 2f oc /proc --dev /
7490: 64 65 76 20 2d 2d 74 6d 70 66 73 20 2f 74 6d 70 dev --tmpfs /tmp
74a0: 60 3b 0a 20 20 20 20 2d 20 60 2d 2d 72 6f 2d 62 `;. - `--ro-b
74b0: 69 6e 64 20 52 45 4c 45 41 53 45 5f 44 49 52 2f ind RELEASE_DIR/
74c0: 6f 63 78 32 20 2f 72 65 6c 65 61 73 65 2f 6f 63 ocx2 /release/oc
74d0: 78 32 2d 63 67 69 60 3b 0a 20 20 20 20 2d 20 60 x2-cgi`;. - `
74e0: 2d 2d 73 65 74 65 6e 76 60 20 66 6f 72 20 65 61 --setenv` for ea
74f0: 63 68 20 6f 66 20 60 52 45 51 55 45 53 54 5f 4d ch of `REQUEST_M
7500: 45 54 48 4f 44 20 51 55 45 52 59 5f 53 54 52 49 ETHOD QUERY_STRI
7510: 4e 47 20 50 41 54 48 5f 49 4e 46 4f 0a 20 20 20 NG PATH_INFO.
7520: 20 20 20 43 4f 4e 54 45 4e 54 5f 4c 45 4e 47 54 CONTENT_LENGT
7530: 48 20 43 4f 4e 54 45 4e 54 5f 54 59 50 45 20 48 H CONTENT_TYPE H
7540: 54 54 50 53 20 48 54 54 50 5f 48 4f 53 54 20 48 TTPS HTTP_HOST H
7550: 54 54 50 5f 52 45 46 45 52 45 52 20 46 4f 53 53 TTP_REFERER FOSS
7560: 49 4c 5f 55 53 45 52 0a 20 20 20 20 20 20 46 4f IL_USER. FO
7570: 53 53 49 4c 5f 43 41 50 41 42 49 4c 49 54 49 45 SSIL_CAPABILITIE
7580: 53 20 46 4f 53 53 49 4c 5f 55 52 49 60 20 74 68 S FOSSIL_URI` th
7590: 61 74 20 69 73 20 73 65 74 3b 0a 20 20 20 20 2d at is set;. -
75a0: 20 60 46 4f 53 53 49 4c 5f 52 45 50 4f 53 49 54 `FOSSIL_REPOSIT
75b0: 4f 52 59 60 20 73 65 74 20 74 6f 20 74 68 65 20 ORY` set to the
75c0: 72 65 70 6f 73 69 74 6f 72 79 20 6e 61 6d 65 20 repository name
75d0: 6f 6e 6c 79 3b 0a 20 20 20 20 2d 20 6e 65 76 65 only;. - neve
75e0: 72 20 60 48 54 54 50 5f 43 4f 4f 4b 49 45 60 20 r `HTTP_COOKIE`
75f0: 6f 72 20 60 46 4f 53 53 49 4c 5f 4e 4f 4e 43 45 or `FOSSIL_NONCE
7600: 60 3b 0a 20 20 20 20 2d 20 60 2d 2d 73 65 74 65 `;. - `--sete
7610: 6e 76 20 50 41 54 48 20 2f 75 73 72 2f 62 69 6e nv PATH /usr/bin
7620: 60 3b 0a 20 20 20 20 2d 20 74 68 65 6e 20 60 2f `;. - then `/
7630: 72 65 6c 65 61 73 65 2f 6f 63 78 32 2d 63 67 69 release/ocx2-cgi
7640: 20 2d 2d 72 65 63 65 69 70 74 2d 66 64 20 33 60 --receipt-fd 3`
7650: 2e 0a 20 20 2d 20 49 66 20 74 68 65 20 73 6f 63 .. - If the soc
7660: 6b 65 74 20 63 61 6e 6e 6f 74 20 62 65 20 72 65 ket cannot be re
7670: 61 63 68 65 64 2c 20 77 72 69 74 65 20 61 20 43 ached, write a C
7680: 47 49 20 72 65 73 70 6f 6e 73 65 20 61 74 20 6f GI response at o
7690: 6e 63 65 3a 0a 20 20 20 20 60 53 74 61 74 75 73 nce:. `Status
76a0: 3a 20 35 30 33 60 2c 20 60 43 6f 6e 74 65 6e 74 : 503`, `Content
76b0: 2d 54 79 70 65 3a 20 61 70 70 6c 69 63 61 74 69 -Type: applicati
76c0: 6f 6e 2f 6a 73 6f 6e 60 2c 20 61 20 62 6c 61 6e on/json`, a blan
76d0: 6b 20 6c 69 6e 65 2c 20 74 68 65 6e 0a 20 20 20 k line, then.
76e0: 20 60 7b 22 75 6e 61 76 61 69 6c 61 62 6c 65 22 `{"unavailable"
76f0: 3a 20 22 72 65 63 65 69 70 74 20 73 65 72 76 69 : "receipt servi
7700: 63 65 20 6e 6f 74 20 61 6e 73 77 65 72 69 6e 67 ce not answering
7710: 22 7d 60 2e 20 54 68 65 6e 20 65 78 69 74 20 30 "}`. Then exit 0
7720: 2e 0a 2d 20 2a 2a 41 6e 79 20 6f 74 68 65 72 20 ..- **Any other
7730: 60 50 41 54 48 5f 49 4e 46 4f 60 3a 2a 2a 20 74 `PATH_INFO`:** t
7740: 68 69 73 20 69 73 20 61 20 74 65 6d 70 6f 72 61 his is a tempora
7750: 72 79 20 70 61 73 73 74 68 72 6f 75 67 68 2c 20 ry passthrough,
7760: 63 61 6c 6c 65 64 20 45 36 20 69 6e 0a 20 20 74 called E6 in. t
7770: 68 65 20 70 6c 61 6e 2e 20 45 78 65 63 20 60 52 he plan. Exec `R
7780: 45 4c 45 41 53 45 5f 44 49 52 2f 6f 63 78 32 60 ELEASE_DIR/ocx2`
7790: 20 77 69 74 68 20 61 72 67 76 5b 30 5d 20 73 65 with argv[0] se
77a0: 74 20 74 6f 0a 20 20 60 52 45 4c 45 41 53 45 5f t to. `RELEASE_
77b0: 44 49 52 2f 6f 63 78 32 2d 63 67 69 60 2e 20 55 DIR/ocx2-cgi`. U
77c0: 73 65 20 60 4c 69 62 43 2e 65 78 65 63 76 60 2c se `LibC.execv`,
77d0: 20 73 6f 20 74 68 65 20 70 72 6f 67 72 61 6d 20 so the program
77e0: 70 69 63 6b 73 20 69 74 73 20 43 47 49 0a 20 20 picks its CGI.
77f0: 65 6e 74 72 79 20 66 72 6f 6d 20 61 72 67 76 5b entry from argv[
7800: 30 5d 20 61 6e 64 20 66 69 6e 64 73 20 69 74 73 0] and finds its
7810: 20 72 6f 6f 74 20 61 73 20 74 68 65 20 70 61 72 root as the par
7820: 65 6e 74 20 6f 66 20 69 74 73 20 72 65 61 6c 0a ent of its real.
7830: 20 20 64 69 72 65 63 74 6f 72 79 2e 20 54 68 65 directory. The
7840: 20 65 6e 76 69 72 6f 6e 6d 65 6e 74 20 69 73 20 environment is
7850: 75 6e 63 68 61 6e 67 65 64 2e 20 57 72 69 74 65 unchanged. Write
7860: 20 61 20 63 6f 6d 6d 65 6e 74 20 73 61 79 69 6e a comment sayin
7870: 67 20 74 68 69 73 0a 20 20 62 72 61 6e 63 68 20 g this. branch
7880: 67 6f 65 73 20 77 68 65 6e 20 74 68 65 20 43 47 goes when the CG
7890: 49 20 74 61 6c 6b 73 20 74 6f 20 74 68 65 20 64 I talks to the d
78a0: 61 65 6d 6f 6e 2e 0a 0a 2a 2a 28 62 29 20 60 73 aemon...**(b) `s
78b0: 74 61 72 74 2d 6f 63 78 20 5b 2d 2d 73 63 72 61 tart-ocx [--scra
78c0: 74 63 68 20 44 49 52 5d 20 72 65 63 65 69 70 74 tch DIR] receipt
78d0: 73 60 2c 2a 2a 20 73 74 61 72 74 65 64 20 62 79 s`,** started by
78e0: 20 61 20 73 79 73 74 65 6d 64 20 75 6e 69 74 0a a systemd unit.
78f0: 61 73 20 74 68 65 20 61 63 63 6f 75 6e 74 20 46 as the account F
7900: 6f 73 73 69 6c 20 72 75 6e 73 20 61 73 2e 20 45 ossil runs as. E
7910: 78 65 63 20 62 77 72 61 70 20 77 69 74 68 3a 0a xec bwrap with:.
7920: 2d 20 60 2d 2d 75 6e 73 68 61 72 65 2d 61 6c 6c - `--unshare-all
7930: 20 2d 2d 64 69 65 2d 77 69 74 68 2d 70 61 72 65 --die-with-pare
7940: 6e 74 20 2d 2d 6e 65 77 2d 73 65 73 73 69 6f 6e nt --new-session
7950: 20 2d 2d 63 61 70 2d 64 72 6f 70 20 41 4c 4c 20 --cap-drop ALL
7960: 2d 2d 63 6c 65 61 72 65 6e 76 60 3b 0a 2d 20 60 --clearenv`;.- `
7970: 2d 2d 72 6f 2d 62 69 6e 64 20 2f 75 73 72 20 2f --ro-bind /usr /
7980: 75 73 72 60 2c 20 70 6c 75 73 20 60 2d 2d 72 6f usr`, plus `--ro
7990: 2d 62 69 6e 64 2d 74 72 79 60 20 66 6f 72 20 60 -bind-try` for `
79a0: 2f 6c 69 62 60 20 61 6e 64 20 60 2f 6c 69 62 36 /lib` and `/lib6
79b0: 34 60 3b 0a 2d 20 60 2d 2d 64 65 76 20 2f 64 65 4`;.- `--dev /de
79c0: 76 20 2d 2d 74 6d 70 66 73 20 2f 74 6d 70 60 2c v --tmpfs /tmp`,
79d0: 20 61 6e 64 20 6e 6f 20 2f 70 72 6f 63 3b 0a 2d and no /proc;.-
79e0: 20 60 2d 2d 72 6f 2d 62 69 6e 64 20 52 45 50 4f `--ro-bind REPO
79f0: 53 49 54 4f 52 49 45 53 20 52 45 50 4f 53 49 54 SITORIES REPOSIT
7a00: 4f 52 49 45 53 60 3b 0a 2d 20 60 2d 2d 62 69 6e ORIES`;.- `--bin
7a10: 64 20 53 4f 43 4b 45 54 5f 44 49 52 20 53 4f 43 d SOCKET_DIR SOC
7a20: 4b 45 54 5f 44 49 52 60 3b 0a 2d 20 60 2d 2d 72 KET_DIR`;.- `--r
7a30: 6f 2d 62 69 6e 64 20 3c 64 69 72 20 6f 66 20 74 o-bind <dir of t
7a40: 68 69 73 20 65 78 65 63 75 74 61 62 6c 65 3e 2f his executable>/
7a50: 72 65 63 65 69 70 74 73 20 2f 72 65 63 65 69 70 receipts /receip
7a60: 74 73 60 3b 0a 2d 20 74 68 65 6e 20 60 2f 72 65 ts`;.- then `/re
7a70: 63 65 69 70 74 73 20 53 4f 43 4b 45 54 20 52 45 ceipts SOCKET RE
7a80: 50 4f 53 49 54 4f 52 49 45 53 60 2e 0a 0a 54 68 POSITORIES`...Th
7a90: 65 20 72 65 63 65 69 70 74 73 20 62 69 6e 61 72 e receipts binar
7aa0: 79 20 69 73 20 62 75 69 6c 74 20 62 65 73 69 64 y is built besid
7ab0: 65 20 73 74 61 72 74 2d 6f 63 78 2c 20 69 6e 20 e start-ocx, in
7ac0: 61 20 63 68 65 63 6b 6f 75 74 27 73 20 60 62 69 a checkout's `bi
7ad0: 6e 2f 60 2e 0a 0a 2a 2a 28 63 29 20 60 73 74 61 n/`...**(c) `sta
7ae0: 72 74 2d 6f 63 78 20 5b 2d 2d 73 63 72 61 74 63 rt-ocx [--scratc
7af0: 68 20 44 49 52 5d 20 64 61 65 6d 6f 6e 60 2c 2a h DIR] daemon`,*
7b00: 2a 20 73 74 61 72 74 65 64 20 62 79 20 61 20 73 * started by a s
7b10: 79 73 74 65 6d 64 20 75 6e 69 74 20 61 73 0a 74 ystemd unit as.t
7b20: 68 65 20 64 61 65 6d 6f 6e 27 73 20 6f 77 6e 20 he daemon's own
7b30: 61 63 63 6f 75 6e 74 2c 20 6e 6f 74 20 72 6f 6f account, not roo
7b40: 74 2e 20 45 78 65 63 20 62 77 72 61 70 20 77 69 t. Exec bwrap wi
7b50: 74 68 3a 0a 2d 20 60 2d 2d 75 6e 73 68 61 72 65 th:.- `--unshare
7b60: 2d 75 73 65 72 20 2d 2d 75 6e 73 68 61 72 65 2d -user --unshare-
7b70: 69 70 63 20 2d 2d 75 6e 73 68 61 72 65 2d 75 74 ipc --unshare-ut
7b80: 73 60 2e 20 44 6f 20 2a 2a 6e 6f 74 2a 2a 20 75 s`. Do **not** u
7b90: 6e 73 68 61 72 65 20 74 68 65 0a 20 20 70 69 64 nshare the. pid
7ba0: 20 6e 61 6d 65 73 70 61 63 65 2c 20 61 6e 64 20 namespace, and
7bb0: 73 68 61 72 65 20 74 68 65 20 6e 65 74 77 6f 72 share the networ
7bc0: 6b 3a 20 77 61 74 63 68 65 72 73 20 6d 75 73 74 k: watchers must
7bd0: 20 6f 75 74 6c 69 76 65 20 61 20 64 61 65 6d 6f outlive a daemo
7be0: 6e 0a 20 20 72 65 73 74 61 72 74 2c 20 61 6e 64 n. restart, and
7bf0: 20 74 68 65 20 64 61 65 6d 6f 6e 20 72 65 61 63 the daemon reac
7c00: 68 65 73 20 46 6f 73 73 69 6c 20 6f 76 65 72 20 hes Fossil over
7c10: 48 54 54 50 53 2e 0a 2d 20 60 2d 2d 63 6c 65 61 HTTPS..- `--clea
7c20: 72 65 6e 76 60 2c 20 74 68 65 6e 20 60 2d 2d 73 renv`, then `--s
7c30: 65 74 65 6e 76 20 48 4f 4d 45 20 3c 68 6f 6d 65 etenv HOME <home
7c40: 3e 20 2d 2d 73 65 74 65 6e 76 20 50 41 54 48 20 > --setenv PATH
7c50: 2f 75 73 72 2f 62 69 6e 3a 2f 62 69 6e 60 2e 0a /usr/bin:/bin`..
7c60: 2d 20 60 2d 2d 72 6f 2d 62 69 6e 64 60 20 66 6f - `--ro-bind` fo
7c70: 72 20 60 2f 75 73 72 60 3b 20 60 2d 2d 72 6f 2d r `/usr`; `--ro-
7c80: 62 69 6e 64 2d 74 72 79 60 20 66 6f 72 20 60 2f bind-try` for `/
7c90: 6c 69 62 60 2c 20 60 2f 6c 69 62 36 34 60 2c 20 lib`, `/lib64`,
7ca0: 60 2f 62 69 6e 60 2c 0a 20 20 60 2f 73 62 69 6e `/bin`,. `/sbin
7cb0: 60 2c 20 60 2f 65 74 63 2f 73 73 6c 60 2c 20 60 `, `/etc/ssl`, `
7cc0: 2f 65 74 63 2f 70 6b 69 60 2c 20 60 2f 65 74 63 /etc/pki`, `/etc
7cd0: 2f 72 65 73 6f 6c 76 2e 63 6f 6e 66 60 2c 20 60 /resolv.conf`, `
7ce0: 2f 65 74 63 2f 68 6f 73 74 73 60 2c 0a 20 20 60 /etc/hosts`,. `
7cf0: 2f 65 74 63 2f 6e 73 73 77 69 74 63 68 2e 63 6f /etc/nsswitch.co
7d00: 6e 66 60 2c 20 60 2f 65 74 63 2f 70 61 73 73 77 nf`, `/etc/passw
7d10: 64 60 20 61 6e 64 20 60 2f 65 74 63 2f 67 72 6f d` and `/etc/gro
7d20: 75 70 60 2e 0a 2d 20 60 2d 2d 70 72 6f 63 20 2f up`..- `--proc /
7d30: 70 72 6f 63 20 2d 2d 64 65 76 20 2f 64 65 76 20 proc --dev /dev
7d40: 2d 2d 74 6d 70 66 73 20 2f 74 6d 70 20 2d 2d 74 --tmpfs /tmp --t
7d50: 6d 70 66 73 20 3c 68 6f 6d 65 3e 60 2e 0a 2d 20 mpfs <home>`..-
7d60: 45 61 63 68 20 68 6f 6d 65 20 70 61 74 68 20 74 Each home path t
7d70: 68 61 74 20 65 78 69 73 74 73 2c 20 77 69 74 68 hat exists, with
7d80: 20 60 2d 2d 62 69 6e 64 2d 74 72 79 60 20 6f 72 `--bind-try` or
7d90: 20 60 2d 2d 72 6f 2d 62 69 6e 64 2d 74 72 79 60 `--ro-bind-try`
7da0: 20 61 73 0a 20 20 6c 69 73 74 65 64 20 61 62 6f as. listed abo
7db0: 76 65 2e 0a 2d 20 60 2d 2d 62 69 6e 64 20 44 41 ve..- `--bind DA
7dc0: 45 4d 4f 4e 5f 52 4f 4f 54 20 44 41 45 4d 4f 4e EMON_ROOT DAEMON
7dd0: 5f 52 4f 4f 54 60 2e 0a 2d 20 54 68 65 6e 20 60 _ROOT`..- Then `
7de0: 44 41 45 4d 4f 4e 5f 52 4f 4f 54 2f 63 75 72 72 DAEMON_ROOT/curr
7df0: 65 6e 74 2f 6f 63 78 32 20 64 61 65 6d 6f 6e 20 ent/ocx2 daemon
7e00: 44 41 45 4d 4f 4e 5f 52 4f 4f 54 2f 6e 6f 64 65 DAEMON_ROOT/node
7e10: 2f 6e 6f 64 65 73 2e 6a 73 6f 6e 60 2e 0a 0a 42 /nodes.json`...B
7e20: 65 66 6f 72 65 20 65 78 65 63 2c 20 72 65 66 75 efore exec, refu
7e30: 73 65 20 77 69 74 68 20 65 78 69 74 20 32 20 69 se with exit 2 i
7e40: 66 20 61 6e 79 20 62 6f 75 6e 64 20 70 61 74 68 f any bound path
7e50: 20 65 71 75 61 6c 73 2c 20 63 6f 6e 74 61 69 6e equals, contain
7e60: 73 20 6f 72 20 6c 69 65 73 0a 75 6e 64 65 72 20 s or lies.under
7e70: 52 45 50 4f 53 49 54 4f 52 49 45 53 2e 20 43 68 REPOSITORIES. Ch
7e80: 65 63 6b 20 69 74 20 77 69 74 68 20 60 46 69 6c eck it with `Fil
7e90: 65 2e 72 65 61 6c 70 61 74 68 60 20 77 68 65 72 e.realpath` wher
7ea0: 65 20 74 68 65 20 70 61 74 68 20 65 78 69 73 74 e the path exist
7eb0: 73 2e 0a 54 68 69 73 20 69 73 20 74 68 65 20 6f s..This is the o
7ec0: 6e 65 20 67 75 61 72 64 20 6f 6e 20 74 68 65 20 ne guard on the
7ed0: 62 6f 75 6e 64 61 72 79 20 69 74 73 65 6c 66 2e boundary itself.
7ee0: 0a 0a 23 23 20 33 2e 20 60 73 68 61 72 64 2e 79 ..## 3. `shard.y
7ef0: 6d 6c 60 0a 0a 41 64 64 20 74 61 72 67 65 74 73 ml`..Add targets
7f00: 20 60 73 74 61 72 74 2d 6f 63 78 60 20 28 6d 61 `start-ocx` (ma
7f10: 69 6e 20 60 73 63 72 69 70 74 73 2f 73 74 61 72 in `scripts/star
7f20: 74 2d 6f 63 78 2e 63 72 60 29 20 61 6e 64 20 60 t-ocx.cr`) and `
7f30: 72 65 63 65 69 70 74 73 60 20 28 6d 61 69 6e 0a receipts` (main.
7f40: 60 73 63 72 69 70 74 73 2f 72 65 63 65 69 70 74 `scripts/receipt
7f50: 73 2e 63 72 60 29 2e 20 55 70 64 61 74 65 20 74 s.cr`). Update t
7f60: 68 65 20 63 6f 6d 6d 65 6e 74 20 61 62 6f 76 65 he comment above
7f70: 20 74 68 65 20 74 61 72 67 65 74 73 3a 20 74 68 the targets: th
7f80: 65 20 66 6f 75 72 0a 62 75 69 6c 74 20 66 72 6f e four.built fro
7f90: 6d 20 73 63 72 69 70 74 73 2f 20 61 72 65 20 74 m scripts/ are t
7fa0: 68 65 20 6d 61 69 6e 74 61 69 6e 65 72 27 73 2e he maintainer's.
7fb0: 0a 0a 23 23 20 44 6f 6e 65 20 77 68 65 6e 0a 0a ..## Done when..
7fc0: 2d 20 60 63 72 79 73 74 61 6c 20 62 75 69 6c 64 - `crystal build
7fd0: 20 2d 2d 6e 6f 2d 63 6f 64 65 67 65 6e 60 20 70 --no-codegen` p
7fe0: 61 73 73 65 73 20 66 6f 72 20 62 6f 74 68 20 66 asses for both f
7ff0: 69 6c 65 73 2e 0a 2d 20 60 63 72 79 73 74 61 6c iles..- `crystal
8000: 20 74 6f 6f 6c 20 66 6f 72 6d 61 74 20 2d 2d 63 tool format --c
8010: 68 65 63 6b 60 20 70 61 73 73 65 73 2e 0a 2d 20 heck` passes..-
8020: 50 72 69 6e 74 20 74 68 65 20 66 75 6c 6c 20 64 Print the full d
8030: 69 66 66 2e 0a 0a 59 6f 75 20 63 61 6e 6e 6f 74 iff...You cannot
8040: 20 6f 70 65 6e 20 73 6f 63 6b 65 74 73 20 6f 72 open sockets or
8050: 20 72 75 6e 20 62 77 72 61 70 20 69 6e 20 79 6f run bwrap in yo
8060: 75 72 20 73 61 6e 64 62 6f 78 2c 20 73 6f 20 64 ur sandbox, so d
8070: 6f 20 6e 6f 74 20 74 72 79 2e 20 54 68 65 0a 72 o not try. The.r
8080: 65 76 69 65 77 65 72 20 72 75 6e 73 20 74 68 65 eviewer runs the
8090: 20 73 70 65 63 73 20 61 6e 64 20 74 68 65 20 73 specs and the s
80a0: 63 72 61 74 63 68 20 64 65 70 6c 6f 79 6d 65 6e cratch deploymen
80b0: 74 2e 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 t...............
80c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
80d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
80e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
80f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
81a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
81b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
81c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
81d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
81e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
81f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8200: 73 74 61 67 65 41 2d 72 65 63 6f 72 64 2f 73 74 stageA-record/st
8210: 61 67 65 41 2d 6f 63 78 2d 70 6c 61 6e 2e 6d 64 ageA-ocx-plan.md
8220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8260: 00 00 00 00 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000
8270: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
8280: 30 30 31 35 30 37 36 00 31 35 32 37 30 34 37 36 0015076.15270476
8290: 32 30 35 00 30 31 35 35 32 32 00 20 30 00 00 00 205.015522. 0...
82a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
82b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
82c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
82d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
82e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
82f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8300: 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
8310: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8320: 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
8330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
83a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
83b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
83c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
83d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
83e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
83f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
8400: 23 20 53 74 61 67 65 20 41 2c 20 74 68 65 20 4f # Stage A, the O
8410: 43 58 20 73 69 64 65 0a 0a 54 68 65 73 65 20 61 CX side..These a
8420: 72 65 20 74 68 65 20 74 77 6f 20 4f 43 58 20 63 re the two OCX c
8430: 68 61 6e 67 65 73 20 74 68 65 20 6e 65 77 20 6c hanges the new l
8440: 61 75 6e 63 68 65 72 20 28 60 73 63 72 69 70 74 auncher (`script
8450: 73 2f 73 74 61 72 74 2d 6f 63 78 2e 63 72 60 29 s/start-ocx.cr`)
8460: 0a 61 6e 64 20 74 68 65 20 72 65 63 65 69 70 74 .and the receipt
8470: 20 73 65 72 76 69 63 65 20 28 60 73 63 72 69 70 service (`scrip
8480: 74 73 2f 72 65 63 65 69 70 74 73 2e 63 72 60 29 ts/receipts.cr`)
8490: 20 6e 65 65 64 2e 20 52 65 61 64 20 62 6f 74 68 need. Read both
84a0: 20 73 63 72 69 70 74 73 0a 66 69 72 73 74 2e 20 scripts.first.
84b0: 44 6f 20 6e 6f 74 20 65 64 69 74 20 61 6e 79 74 Do not edit anyt
84c0: 68 69 6e 67 20 69 6e 20 60 73 63 72 69 70 74 73 hing in `scripts
84d0: 2f 60 20 6f 72 20 60 73 68 61 72 64 2e 79 6d 6c /` or `shard.yml
84e0: 60 2e 20 46 6f 6c 6c 6f 77 0a 60 64 6f 63 73 2f `. Follow.`docs/
84f0: 63 72 79 73 74 61 6c 2e 6d 64 60 20 61 6e 64 20 crystal.md` and
8500: 74 68 65 20 70 72 65 63 65 70 74 73 20 69 6e 20 the precepts in
8510: 60 50 4c 41 4e 2e 6d 64 60 3b 20 74 68 65 20 67 `PLAN.md`; the g
8520: 61 74 65 27 73 20 67 75 61 72 64 73 20 68 6f 6c ate's guards hol
8530: 64 0a 65 76 65 72 79 20 63 68 61 6e 67 65 20 74 d.every change t
8540: 6f 20 74 68 65 6d 2e 20 4b 65 65 70 20 65 76 65 o them. Keep eve
8550: 72 79 20 66 69 6c 65 20 77 69 74 68 69 6e 20 34 ry file within 4
8560: 30 30 20 6c 69 6e 65 73 2e 0a 0a 23 23 20 31 2e 00 lines...## 1.
8570: 20 54 68 65 20 43 47 49 20 72 65 6c 61 79 73 20 The CGI relays
8580: 60 72 65 63 65 69 70 74 60 20 74 6f 20 74 68 65 `receipt` to the
8590: 20 72 65 63 65 69 70 74 20 73 65 72 76 69 63 65 receipt service
85a0: 0a 0a 54 68 65 20 6c 61 75 6e 63 68 65 72 20 68 ..The launcher h
85b0: 61 6e 64 6c 65 73 20 61 20 72 65 71 75 65 73 74 andles a request
85c0: 20 77 68 6f 73 65 20 60 50 41 54 48 5f 49 4e 46 whose `PATH_INF
85d0: 4f 60 20 69 73 20 60 2f 72 65 63 65 69 70 74 60 O` is `/receipt`
85e0: 20 74 68 69 73 20 77 61 79 3a 0a 2d 20 69 74 20 this way:.- it
85f0: 63 6f 6e 6e 65 63 74 73 20 74 6f 20 74 68 65 20 connects to the
8600: 72 65 63 65 69 70 74 20 73 65 72 76 69 63 65 3b receipt service;
8610: 0a 2d 20 69 74 20 77 72 69 74 65 73 20 74 68 65 .- it writes the
8620: 20 69 64 65 6e 74 69 74 79 20 6c 69 6e 65 20 69 identity line i
8630: 74 73 65 6c 66 3b 0a 2d 20 69 74 20 70 61 73 73 tself;.- it pass
8640: 65 73 20 74 68 65 20 63 6f 6e 6e 65 63 74 69 6f es the connectio
8650: 6e 20 61 73 20 64 65 73 63 72 69 70 74 6f 72 20 n as descriptor
8660: 33 3b 0a 2d 20 69 74 20 73 74 61 72 74 73 20 74 3;.- it starts t
8670: 68 65 20 72 65 6c 65 61 73 65 27 73 20 70 72 6f he release's pro
8680: 67 72 61 6d 2c 20 73 61 6e 64 62 6f 78 65 64 2c gram, sandboxed,
8690: 20 61 73 20 60 6f 63 78 32 2d 63 67 69 20 2d 2d as `ocx2-cgi --
86a0: 72 65 63 65 69 70 74 2d 66 64 20 33 60 2e 0a 0a receipt-fd 3`...
86b0: 49 6e 20 74 68 61 74 20 73 61 6e 64 62 6f 78 20 In that sandbox
86c0: 74 68 65 72 65 20 69 73 20 6e 6f 20 72 65 70 6f there is no repo
86d0: 73 69 74 6f 72 79 20 66 69 6c 65 2c 20 6e 6f 20 sitory file, no
86e0: 60 66 6f 73 73 69 6c 60 20 61 6e 64 20 6e 6f 20 `fossil` and no
86f0: 6e 65 74 77 6f 72 6b 2e 0a 60 46 4f 53 53 49 4c network..`FOSSIL
8700: 5f 52 45 50 4f 53 49 54 4f 52 59 60 20 68 6f 6c _REPOSITORY` hol
8710: 64 73 20 6f 6e 6c 79 20 74 68 65 20 72 65 70 6f ds only the repo
8720: 73 69 74 6f 72 79 27 73 20 6e 61 6d 65 2e 0a 0a sitory's name...
8730: 2d 20 2a 2a 45 6e 74 72 79 20 70 6f 69 6e 74 2a - **Entry point*
8740: 2a 20 28 60 73 72 63 2f 6f 63 78 2f 65 6e 74 72 * (`src/ocx/entr
8750: 79 2e 63 72 60 29 2e 20 57 68 65 6e 20 74 68 65 y.cr`). When the
8760: 20 65 6e 74 72 79 20 70 6f 69 6e 74 20 69 73 20 entry point is
8770: 74 68 65 20 43 47 49 0a 20 20 61 6e 64 20 60 61 the CGI. and `a
8780: 72 67 73 60 20 69 73 20 65 78 61 63 74 6c 79 20 rgs` is exactly
8790: 60 5b 22 2d 2d 72 65 63 65 69 70 74 2d 66 64 22 `["--receipt-fd"
87a0: 2c 20 4e 5d 60 2c 20 77 69 74 68 20 4e 20 61 20 , N]`, with N a
87b0: 64 65 63 69 6d 61 6c 20 64 65 73 63 72 69 70 74 decimal descript
87c0: 6f 72 0a 20 20 6e 75 6d 62 65 72 2c 20 6f 70 65 or. number, ope
87d0: 6e 20 60 49 4f 3a 3a 46 69 6c 65 44 65 73 63 72 n `IO::FileDescr
87e0: 69 70 74 6f 72 2e 6e 65 77 28 4e 2c 20 62 6c 6f iptor.new(N, blo
87f0: 63 6b 69 6e 67 3a 20 74 72 75 65 29 60 20 61 6e cking: true)` an
8800: 64 20 70 75 74 20 69 74 20 69 6e 0a 20 20 74 68 d put it in. th
8810: 65 20 63 6f 6e 74 65 78 74 20 61 73 20 74 68 65 e context as the
8820: 20 72 65 63 65 69 70 74 20 73 65 72 76 69 63 65 receipt service
8830: 27 73 20 63 6f 6e 6e 65 63 74 69 6f 6e 2c 20 61 's connection, a
8840: 20 6e 65 77 20 6e 69 6c 61 62 6c 65 20 66 69 65 new nilable fie
8850: 6c 64 20 6f 66 0a 20 20 60 43 6f 6e 74 65 78 74 ld of. `Context
8860: 60 2e 20 41 6e 79 20 6f 74 68 65 72 20 61 72 67 `. Any other arg
8870: 75 6d 65 6e 74 73 20 67 69 76 65 6e 20 74 6f 20 uments given to
8880: 74 68 65 20 43 47 49 20 61 72 65 20 72 65 66 75 the CGI are refu
8890: 73 65 64 20 61 73 20 61 20 75 73 61 67 65 0a 20 sed as a usage.
88a0: 20 65 72 72 6f 72 2e 20 57 69 74 68 20 6e 6f 20 error. With no
88b0: 61 72 67 75 6d 65 6e 74 73 2c 20 6e 6f 74 68 69 arguments, nothi
88c0: 6e 67 20 63 68 61 6e 67 65 73 2e 0a 2d 20 2a 2a ng changes..- **
88d0: 54 68 65 20 43 47 49 2a 2a 20 28 60 73 72 63 2f The CGI** (`src/
88e0: 6f 63 78 2f 63 67 69 2e 63 72 60 29 2e 20 57 69 ocx/cgi.cr`). Wi
88f0: 74 68 20 74 68 61 74 20 63 6f 6e 6e 65 63 74 69 th that connecti
8900: 6f 6e 20 73 65 74 2c 20 74 68 65 20 70 61 67 65 on set, the page
8910: 0a 20 20 61 6e 73 77 65 72 73 20 6f 6e 6c 79 20 . answers only
8920: 74 68 65 20 74 6f 6f 6c 20 60 72 65 63 65 69 70 the tool `receip
8930: 74 60 2e 20 41 6e 79 20 6f 74 68 65 72 20 74 6f t`. Any other to
8940: 6f 6c 20 6e 61 6d 65 20 69 73 20 72 65 66 75 73 ol name is refus
8950: 65 64 2c 20 73 61 79 69 6e 67 0a 20 20 74 68 61 ed, saying. tha
8960: 74 20 74 68 69 73 20 73 61 6e 64 62 6f 78 20 61 t this sandbox a
8970: 6e 73 77 65 72 73 20 6f 6e 6c 79 20 60 72 65 63 nswers only `rec
8980: 65 69 70 74 60 2e 20 54 68 65 20 72 65 71 75 65 eipt`. The reque
8990: 73 74 27 73 20 66 69 65 6c 64 73 20 72 65 61 63 st's fields reac
89a0: 68 20 74 68 65 0a 20 20 74 6f 6f 6c 20 61 73 20 h the. tool as
89b0: 74 68 65 79 20 64 6f 20 74 6f 64 61 79 20 28 66 they do today (f
89c0: 6f 72 6d 20 61 6e 64 20 71 75 65 72 79 20 66 69 orm and query fi
89d0: 65 6c 64 73 20 60 61 72 74 69 66 61 63 74 73 60 elds `artifacts`
89e0: 2c 0a 20 20 60 63 61 70 61 62 69 6c 69 74 69 65 ,. `capabilitie
89f0: 73 5f 6f 66 60 20 61 6e 64 20 60 6a 73 6f 6e 60 s_of` and `json`
8a00: 29 2e 0a 2d 20 2a 2a 54 68 65 20 72 65 63 65 69 )..- **The recei
8a10: 70 74 20 74 6f 6f 6c 2a 2a 20 28 60 73 72 63 2f pt tool** (`src/
8a20: 6f 63 78 2f 63 6f 6d 6d 61 6e 64 73 2f 72 65 63 ocx/commands/rec
8a30: 65 69 70 74 2e 63 72 60 29 2e 20 57 68 65 6e 20 eipt.cr`). When
8a40: 74 68 65 20 63 6f 6e 74 65 78 74 0a 20 20 68 6f the context. ho
8a50: 6c 64 73 20 74 68 65 20 63 6f 6e 6e 65 63 74 69 lds the connecti
8a60: 6f 6e 2c 20 60 72 75 6e 60 20 61 73 6b 73 20 74 on, `run` asks t
8a70: 68 65 20 73 65 72 76 69 63 65 20 61 6e 64 20 6e he service and n
8a80: 6f 74 68 69 6e 67 20 65 6c 73 65 2e 20 49 74 20 othing else. It
8a90: 62 75 69 6c 64 73 0a 20 20 6e 6f 20 60 46 6f 73 builds. no `Fos
8aa0: 73 69 6c 3a 3a 50 6c 61 63 65 60 2c 20 72 65 61 sil::Place`, rea
8ab0: 64 73 20 6e 6f 20 72 65 70 6f 73 69 74 6f 72 79 ds no repository
8ac0: 20 61 6e 64 20 72 75 6e 73 20 6e 6f 20 70 72 6f and runs no pro
8ad0: 63 65 73 73 2e 0a 20 20 2d 20 49 74 20 76 61 6c cess.. - It val
8ae0: 69 64 61 74 65 73 20 69 6e 70 75 74 20 61 73 20 idates input as
8af0: 74 6f 64 61 79 3a 20 65 61 63 68 20 61 72 74 69 today: each arti
8b00: 66 61 63 74 20 61 20 68 61 73 68 20 69 6e 20 66 fact a hash in f
8b10: 75 6c 6c 2e 0a 20 20 2d 20 41 64 64 20 61 20 74 ull.. - Add a t
8b20: 79 70 65 64 20 63 68 65 63 6b 20 6f 70 65 72 61 yped check opera
8b30: 74 69 6f 6e 2c 20 60 41 73 6b 52 65 63 65 69 70 tion, `AskReceip
8b40: 74 53 65 72 76 69 63 65 60 2c 20 6c 6f 67 67 65 tService`, logge
8b50: 64 20 6c 69 6b 65 0a 20 20 20 20 60 41 73 6b 53 d like. `AskS
8b60: 65 72 76 65 72 52 65 63 65 69 70 74 73 60 3a 20 erverReceipts`:
8b70: 74 68 65 20 63 6f 75 6e 74 20 6f 66 20 61 72 74 the count of art
8b80: 69 66 61 63 74 73 20 61 6e 64 20 74 68 65 20 75 ifacts and the u
8b90: 73 65 72 2c 20 6e 65 76 65 72 20 74 68 65 0a 20 ser, never the.
8ba0: 20 20 20 68 61 73 68 65 73 2e 0a 20 20 2d 20 49 hashes.. - I
8bb0: 74 20 77 72 69 74 65 73 20 6f 6e 65 20 6c 69 6e t writes one lin
8bc0: 65 2c 0a 20 20 20 20 60 7b 22 6f 63 78 5f 72 65 e,. `{"ocx_re
8bd0: 63 65 69 70 74 22 3a 20 31 2c 20 22 61 72 74 69 ceipt": 1, "arti
8be0: 66 61 63 74 73 22 3a 20 5b 2e 2e 2e 5d 2c 20 22 facts": [...], "
8bf0: 63 61 70 61 62 69 6c 69 74 69 65 73 5f 6f 66 22 capabilities_of"
8c00: 3a 20 55 7d 60 2e 20 4c 65 61 76 65 0a 20 20 20 : U}`. Leave.
8c10: 20 6f 75 74 20 60 61 72 74 69 66 61 63 74 73 60 out `artifacts`
8c20: 20 77 68 65 6e 20 74 68 65 72 65 20 61 72 65 20 when there are
8c30: 6e 6f 6e 65 2c 20 61 6e 64 20 60 63 61 70 61 62 none, and `capab
8c40: 69 6c 69 74 69 65 73 5f 6f 66 60 20 77 68 65 6e ilities_of` when
8c50: 20 6e 6f 6e 65 0a 20 20 20 20 77 61 73 20 61 73 none. was as
8c60: 6b 65 64 2e 0a 20 20 2d 20 49 74 20 72 65 61 64 ked.. - It read
8c70: 73 20 6f 6e 65 20 6c 69 6e 65 20 6f 66 20 61 74 s one line of at
8c80: 20 6d 6f 73 74 20 31 20 4d 69 42 20 77 69 74 68 most 1 MiB with
8c90: 69 6e 20 31 30 20 73 65 63 6f 6e 64 73 2c 20 61 in 10 seconds, a
8ca0: 6e 64 20 6d 61 70 73 20 69 74 3a 0a 20 20 20 20 nd maps it:.
8cb0: 2d 20 60 7b 22 61 72 74 69 66 61 63 74 73 22 3a - `{"artifacts":
8cc0: 20 5b 2e 2e 2e 5d 2c 20 22 75 73 65 72 22 3a 20 [...], "user":
8cd0: 7b 2e 2e 2e 7d 3f 7d 60 20 62 65 63 6f 6d 65 73 {...}?}` becomes
8ce0: 20 60 4f 75 74 70 75 74 60 2c 20 77 69 74 68 20 `Output`, with
8cf0: 74 68 65 0a 20 20 20 20 20 20 73 61 6d 65 20 60 the. same `
8d00: 52 65 63 65 69 76 65 64 60 20 61 6e 64 20 60 48 Received` and `H
8d10: 65 6c 64 60 20 76 61 6c 75 65 73 2c 20 60 63 61 eld` values, `ca
8d20: 70 61 62 69 6c 69 74 69 65 73 60 20 70 61 72 73 pabilities` pars
8d30: 65 64 20 61 73 0a 20 20 20 20 20 20 60 43 61 70 ed as. `Cap
8d40: 61 62 69 6c 69 74 69 65 73 60 2e 20 54 68 65 20 abilities`. The
8d50: 61 6e 73 77 65 72 20 69 73 20 72 65 66 75 73 65 answer is refuse
8d60: 64 20 75 6e 6c 65 73 73 20 69 74 73 20 61 72 74 d unless its art
8d70: 69 66 61 63 74 73 20 61 72 65 20 74 68 65 0a 20 ifacts are the.
8d80: 20 20 20 20 20 6f 6e 65 73 20 61 73 6b 65 64 2c ones asked,
8d90: 20 69 6e 20 6f 72 64 65 72 2c 20 61 6e 64 20 69 in order, and i
8da0: 74 73 20 75 73 65 72 20 74 68 65 20 6f 6e 65 20 ts user the one
8db0: 61 73 6b 65 64 2c 20 61 73 0a 20 20 20 20 20 20 asked, as.
8dc0: 60 41 73 6b 53 65 72 76 65 72 52 65 63 65 69 70 `AskServerReceip
8dd0: 74 73 60 20 63 68 65 63 6b 73 20 74 6f 64 61 79 ts` checks today
8de0: 2e 0a 20 20 20 20 2d 20 60 7b 22 72 65 66 75 73 .. - `{"refus
8df0: 65 64 22 3a 20 52 7d 60 20 62 65 63 6f 6d 65 73 ed": R}` becomes
8e00: 20 61 20 72 65 66 75 73 61 6c 20 6e 61 6d 69 6e a refusal namin
8e10: 67 20 52 2e 0a 20 20 20 20 2d 20 60 7b 22 75 6e g R.. - `{"un
8e20: 61 76 61 69 6c 61 62 6c 65 22 3a 20 52 7d 60 20 available": R}`
8e30: 62 65 63 6f 6d 65 73 20 61 20 72 65 66 75 73 61 becomes a refusa
8e40: 6c 3a 20 22 74 68 65 20 72 65 63 65 69 70 74 20 l: "the receipt
8e50: 73 65 72 76 69 63 65 20 69 73 0a 20 20 20 20 20 service is.
8e60: 20 75 6e 61 76 61 69 6c 61 62 6c 65 3a 20 52 22 unavailable: R"
8e70: 2e 0a 20 20 20 20 2d 20 41 6e 79 74 68 69 6e 67 .. - Anything
8e80: 20 65 6c 73 65 2c 20 6f 72 20 6e 6f 20 6c 69 6e else, or no lin
8e90: 65 20 69 6e 20 74 69 6d 65 2c 20 69 73 20 72 65 e in time, is re
8ea0: 66 75 73 65 64 20 61 73 20 22 74 68 65 20 72 65 fused as "the re
8eb0: 63 65 69 70 74 0a 20 20 20 20 20 20 73 65 72 76 ceipt. serv
8ec0: 69 63 65 20 64 69 64 20 6e 6f 74 20 61 6e 73 77 ice did not answ
8ed0: 65 72 22 2e 0a 20 20 2d 20 54 68 65 20 4a 53 4f er".. - The JSO
8ee0: 4e 20 61 6e 73 77 65 72 27 73 20 73 68 61 70 65 N answer's shape
8ef0: 20 69 73 20 65 78 61 63 74 6c 79 20 74 6f 64 61 is exactly toda
8f00: 79 27 73 2c 20 73 6f 20 74 68 65 20 64 61 65 6d y's, so the daem
8f10: 6f 6e 27 73 20 61 6e 64 0a 20 20 20 20 6e 6f 64 on's and. nod
8f20: 65 73 27 20 60 53 65 72 76 65 72 60 20 63 6c 69 es' `Server` cli
8f30: 65 6e 74 20 72 65 61 64 69 6e 67 20 60 2f 65 78 ent reading `/ex
8f40: 74 2f 6f 63 78 32 2d 63 67 69 2f 72 65 63 65 69 t/ocx2-cgi/recei
8f50: 70 74 60 20 77 69 74 68 20 60 6a 73 6f 6e 3d 6f pt` with `json=o
8f60: 6e 60 0a 20 20 20 20 69 73 20 75 6e 63 68 61 6e n`. is unchan
8f70: 67 65 64 2e 0a 2d 20 2a 2a 53 70 65 63 2c 2a 2a ged..- **Spec,**
8f80: 20 60 73 70 65 63 2f 6f 63 78 2f 72 65 63 65 69 `spec/ocx/recei
8f90: 70 74 5f 73 65 72 76 69 63 65 5f 73 70 65 63 2e pt_service_spec.
8fa0: 63 72 60 2e 20 55 73 65 20 60 55 4e 49 58 53 6f cr`. Use `UNIXSo
8fb0: 63 6b 65 74 2e 70 61 69 72 60 2c 0a 20 20 6f 6e cket.pair`,. on
8fc0: 65 20 65 6e 64 20 69 6e 20 74 68 65 20 63 6f 6e e end in the con
8fd0: 74 65 78 74 20 61 6e 64 20 74 68 65 20 6f 74 68 text and the oth
8fe0: 65 72 20 72 65 61 64 20 62 79 20 61 20 66 69 62 er read by a fib
8ff0: 65 72 20 73 74 61 6e 64 69 6e 67 20 69 6e 20 66 er standing in f
9000: 6f 72 0a 20 20 74 68 65 20 73 65 72 76 69 63 65 or. the service
9010: 2e 20 53 68 6f 77 3a 0a 20 20 2d 20 74 68 65 20 . Show:. - the
9020: 65 78 61 63 74 20 72 65 71 75 65 73 74 20 6c 69 exact request li
9030: 6e 65 20 66 6f 72 20 61 72 74 69 66 61 63 74 73 ne for artifacts
9040: 20 61 6e 64 20 66 6f 72 20 61 20 75 73 65 72 3b and for a user;
9050: 0a 20 20 2d 20 61 6e 20 61 6e 73 77 65 72 20 6d . - an answer m
9060: 61 70 70 65 64 20 74 6f 20 74 68 65 20 73 61 6d apped to the sam
9070: 65 20 4a 53 4f 4e 20 74 68 65 20 73 65 72 76 65 e JSON the serve
9080: 64 20 72 65 70 6f 73 69 74 6f 72 79 27 73 20 60 d repository's `
9090: 72 65 63 65 69 70 74 60 0a 20 20 20 20 67 69 76 receipt`. giv
90a0: 65 73 3b 0a 20 20 2d 20 60 72 65 66 75 73 65 64 es;. - `refused
90b0: 60 2c 20 60 75 6e 61 76 61 69 6c 61 62 6c 65 60 `, `unavailable`
90c0: 2c 20 61 20 77 72 6f 6e 67 20 61 72 74 69 66 61 , a wrong artifa
90d0: 63 74 20 6f 72 64 65 72 20 61 6e 64 20 73 69 6c ct order and sil
90e0: 65 6e 63 65 2c 20 65 61 63 68 20 61 0a 20 20 20 ence, each a.
90f0: 20 72 65 66 75 73 61 6c 3b 0a 20 20 2d 20 61 6e refusal;. - an
9100: 79 20 74 6f 6f 6c 20 62 75 74 20 60 72 65 63 65 y tool but `rece
9110: 69 70 74 60 20 72 65 66 75 73 65 64 20 61 74 20 ipt` refused at
9120: 74 68 65 20 43 47 49 20 77 69 74 68 20 74 68 65 the CGI with the
9130: 20 63 6f 6e 6e 65 63 74 69 6f 6e 20 73 65 74 3b connection set;
9140: 0a 20 20 2d 20 6e 6f 20 66 6f 73 73 69 6c 20 63 . - no fossil c
9150: 6f 6d 6d 61 6e 64 20 72 75 6e 20 61 74 20 61 6c ommand run at al
9160: 6c 2e 20 55 73 65 20 74 68 65 20 73 74 61 6e 64 l. Use the stand
9170: 2d 69 6e 20 66 6f 73 73 69 6c 20 69 6e 0a 20 20 -in fossil in.
9180: 20 20 60 73 70 65 63 2f 73 75 70 70 6f 72 74 2f `spec/support/
9190: 73 74 61 6e 64 5f 69 6e 5f 66 6f 73 73 69 6c 2e stand_in_fossil.
91a0: 63 72 60 2c 20 61 73 20 6f 74 68 65 72 20 73 70 cr`, as other sp
91b0: 65 63 73 20 64 6f 2c 20 61 6e 64 20 63 68 65 63 ecs do, and chec
91c0: 6b 20 69 74 0a 20 20 20 20 72 65 63 6f 72 64 65 k it. recorde
91d0: 64 20 6e 6f 74 68 69 6e 67 3b 0a 20 20 2d 20 74 d nothing;. - t
91e0: 68 65 20 43 47 49 20 65 6e 74 72 79 20 72 65 66 he CGI entry ref
91f0: 75 73 69 6e 67 20 65 78 74 72 61 20 61 72 67 75 using extra argu
9200: 6d 65 6e 74 73 2e 0a 0a 23 23 20 32 2e 20 60 6d ments...## 2. `m
9210: 69 67 72 61 74 65 60 27 73 20 75 6e 69 74 20 73 igrate`'s unit s
9220: 74 61 72 74 73 20 74 68 65 20 64 61 65 6d 6f 6e tarts the daemon
9230: 20 74 68 72 6f 75 67 68 20 74 68 65 20 6c 61 75 through the lau
9240: 6e 63 68 65 72 2c 20 61 73 20 69 74 73 20 6f 77 ncher, as its ow
9250: 6e 20 61 63 63 6f 75 6e 74 0a 0a 2d 20 60 4d 69 n account..- `Mi
9260: 67 72 61 74 69 6f 6e 2e 75 6e 69 74 60 20 28 60 gration.unit` (`
9270: 73 72 63 2f 6f 63 78 2f 6d 69 67 72 61 74 69 6f src/ocx/migratio
9280: 6e 2e 63 72 60 29 20 74 61 6b 65 73 20 74 68 65 n.cr`) takes the
9290: 20 6c 61 75 6e 63 68 65 72 27 73 20 70 61 74 68 launcher's path
92a0: 20 61 6e 64 0a 20 20 74 68 65 20 61 63 63 6f 75 and. the accou
92b0: 6e 74 2e 20 54 68 65 20 75 6e 69 74 20 62 65 63 nt. The unit bec
92c0: 6f 6d 65 73 3a 0a 20 20 60 60 60 0a 20 20 5b 55 omes:. ```. [U
92d0: 6e 69 74 5d 0a 20 20 53 74 61 72 74 4c 69 6d 69 nit]. StartLimi
92e0: 74 49 6e 74 65 72 76 61 6c 53 65 63 3d 30 0a 20 tIntervalSec=0.
92f0: 20 5b 53 65 72 76 69 63 65 5d 0a 20 20 55 73 65 [Service]. Use
9300: 72 3d 41 43 43 4f 55 4e 54 0a 20 20 45 78 65 63 r=ACCOUNT. Exec
9310: 53 74 61 72 74 3d 53 54 41 52 54 5f 4f 43 58 20 Start=START_OCX
9320: 64 61 65 6d 6f 6e 0a 20 20 52 65 73 74 61 72 74 daemon. Restart
9330: 3d 61 6c 77 61 79 73 0a 20 20 52 65 73 74 61 72 =always. Restar
9340: 74 53 65 63 3d 31 30 0a 20 20 4b 69 6c 6c 4d 6f tSec=10. KillMo
9350: 64 65 3d 70 72 6f 63 65 73 73 0a 20 20 5b 49 6e de=process. [In
9360: 73 74 61 6c 6c 5d 0a 20 20 57 61 6e 74 65 64 42 stall]. WantedB
9370: 79 3d 6d 75 6c 74 69 2d 75 73 65 72 2e 74 61 72 y=multi-user.tar
9380: 67 65 74 0a 20 20 60 60 60 0a 2d 20 60 6d 69 67 get. ```.- `mig
9390: 72 61 74 65 60 20 28 60 73 72 63 2f 6f 63 78 2f rate` (`src/ocx/
93a0: 63 6f 6d 6d 61 6e 64 73 2f 6d 69 67 72 61 74 65 commands/migrate
93b0: 2e 63 72 60 29 20 67 61 69 6e 73 20 74 77 6f 20 .cr`) gains two
93c0: 72 65 71 75 69 72 65 64 20 6f 70 74 69 6f 6e 73 required options
93d0: 3a 0a 20 20 2d 20 60 2d 2d 73 74 61 72 74 2d 6f :. - `--start-o
93e0: 63 78 20 50 41 54 48 60 2c 20 61 6e 20 61 62 73 cx PATH`, an abs
93f0: 6f 6c 75 74 65 20 70 61 74 68 3b 0a 20 20 2d 20 olute path;. -
9400: 60 2d 2d 61 63 63 6f 75 6e 74 20 4e 41 4d 45 60 `--account NAME`
9410: 2c 20 61 20 75 73 65 72 20 6e 61 6d 65 20 6f 66 , a user name of
9420: 20 6c 6f 77 65 72 2d 63 61 73 65 20 6c 65 74 74 lower-case lett
9430: 65 72 73 2c 20 64 69 67 69 74 73 2c 20 60 2d 60 ers, digits, `-`
9440: 20 61 6e 64 0a 20 20 20 20 60 5f 60 2c 20 6e 6f and. `_`, no
9450: 74 20 60 72 6f 6f 74 60 2e 20 41 20 72 65 66 75 t `root`. A refu
9460: 73 61 6c 20 73 61 79 73 20 77 68 79 3a 20 74 68 sal says why: th
9470: 65 20 64 61 65 6d 6f 6e 20 72 75 6e 73 20 61 73 e daemon runs as
9480: 20 61 6e 20 61 63 63 6f 75 6e 74 20 6f 66 0a 20 an account of.
9490: 20 20 20 69 74 73 20 6f 77 6e 2c 20 73 6f 20 69 its own, so i
94a0: 74 20 63 61 6e 6e 6f 74 20 72 65 61 64 20 74 68 t cannot read th
94b0: 65 20 73 65 72 76 65 64 20 72 65 70 6f 73 69 74 e served reposit
94c0: 6f 72 69 65 73 2c 20 61 6e 64 20 6f 6e 6c 79 20 ories, and only
94d0: 61 0a 20 20 20 20 6c 61 75 6e 63 68 65 72 20 66 a. launcher f
94e0: 69 78 65 64 20 62 79 20 74 68 65 20 6d 61 69 6e ixed by the main
94f0: 74 61 69 6e 65 72 20 73 74 61 72 74 73 20 69 74 tainer starts it
9500: 2e 0a 20 20 42 6f 74 68 20 61 72 65 20 65 78 70 .. Both are exp
9510: 6c 69 63 69 74 20 61 72 67 75 6d 65 6e 74 73 20 licit arguments
9520: 28 70 72 65 63 65 70 74 20 43 36 2c 20 45 78 70 (precept C6, Exp
9530: 6c 69 63 69 74 20 41 72 67 75 6d 65 6e 74 73 29 licit Arguments)
9540: 2e 0a 20 20 2d 20 54 68 65 20 64 61 65 6d 6f 6e .. - The daemon
9550: 27 73 20 52 4f 4f 54 20 6d 75 73 74 20 62 65 20 's ROOT must be
9560: 74 68 65 20 6c 61 75 6e 63 68 65 72 27 73 3a 20 the launcher's:
9570: 74 68 65 20 6c 61 75 6e 63 68 65 72 20 68 6f 6c the launcher hol
9580: 64 73 0a 20 20 20 20 60 2f 76 61 72 2f 6c 69 62 ds. `/var/lib
9590: 2f 6f 63 78 2f 61 67 65 6e 74 73 2d 64 61 65 6d /ocx/agents-daem
95a0: 6f 6e 60 20 6f 6e 20 74 68 65 20 6c 69 76 65 20 on` on the live
95b0: 68 6f 73 74 2e 20 60 6d 69 67 72 61 74 65 60 20 host. `migrate`
95c0: 63 61 6e 6e 6f 74 20 72 65 61 64 0a 20 20 20 20 cannot read.
95d0: 74 68 61 74 2c 20 73 6f 20 60 64 6f 63 73 2f 6d that, so `docs/m
95e0: 69 67 72 61 74 65 2e 6d 64 60 20 73 61 79 73 20 igrate.md` says
95f0: 73 6f 2e 0a 2d 20 55 70 64 61 74 65 20 60 73 70 so..- Update `sp
9600: 65 63 2f 6f 63 78 2f 6d 69 67 72 61 74 65 5f 73 ec/ocx/migrate_s
9610: 70 65 63 2e 63 72 60 2c 20 60 73 70 65 63 2f 6f pec.cr`, `spec/o
9620: 63 78 2f 6d 69 67 72 61 74 65 5f 72 65 66 75 73 cx/migrate_refus
9630: 61 6c 73 5f 73 70 65 63 2e 63 72 60 2c 0a 20 20 als_spec.cr`,.
9640: 61 6e 64 20 61 6e 79 74 68 69 6e 67 20 65 6c 73 and anything els
9650: 65 20 74 68 61 74 20 72 75 6e 73 20 60 6d 69 67 e that runs `mig
9660: 72 61 74 65 60 2c 20 73 6f 20 65 76 65 72 79 20 rate`, so every
9670: 63 61 6c 6c 20 70 61 73 73 65 73 20 62 6f 74 68 call passes both
9680: 0a 20 20 6f 70 74 69 6f 6e 73 2e 20 41 64 64 20 . options. Add
9690: 61 20 72 65 66 75 73 61 6c 20 65 78 61 6d 70 6c a refusal exampl
96a0: 65 20 66 6f 72 20 60 2d 2d 61 63 63 6f 75 6e 74 e for `--account
96b0: 20 72 6f 6f 74 60 20 61 6e 64 20 66 6f 72 20 61 root` and for a
96c0: 20 72 65 6c 61 74 69 76 65 0a 20 20 60 2d 2d 73 relative. `--s
96d0: 74 61 72 74 2d 6f 63 78 60 2e 0a 2d 20 2a 2a 55 tart-ocx`..- **U
96e0: 53 41 47 45 2e 6d 64 3a 2a 2a 20 69 74 73 20 75 SAGE.md:** its u
96f0: 6e 69 74 20 74 65 78 74 20 6d 75 73 74 20 65 71 nit text must eq
9700: 75 61 6c 20 60 4d 69 67 72 61 74 69 6f 6e 2e 75 ual `Migration.u
9710: 6e 69 74 60 27 73 2c 20 61 73 20 74 68 65 20 73 nit`'s, as the s
9720: 70 65 63 0a 20 20 63 6f 6d 70 61 72 65 73 20 74 pec. compares t
9730: 68 65 6d 2e 20 53 68 6f 77 20 74 68 65 20 6e 65 hem. Show the ne
9740: 77 20 75 6e 69 74 2c 20 61 6e 64 20 73 61 79 20 w unit, and say
9750: 69 6e 20 6f 6e 65 20 6f 72 20 74 77 6f 20 73 65 in one or two se
9760: 6e 74 65 6e 63 65 73 20 77 68 79 3a 0a 20 20 2d ntences why:. -
9770: 20 74 68 65 20 64 61 65 6d 6f 6e 20 72 75 6e 73 the daemon runs
9780: 20 61 73 20 61 6e 20 61 63 63 6f 75 6e 74 20 6f as an account o
9790: 66 20 69 74 73 20 6f 77 6e 2c 20 75 6e 64 65 72 f its own, under
97a0: 20 74 68 65 20 6d 61 69 6e 74 61 69 6e 65 72 27 the maintainer'
97b0: 73 0a 20 20 20 20 6c 61 75 6e 63 68 65 72 2c 20 s. launcher,
97c0: 69 6e 73 69 64 65 20 61 20 6d 6f 75 6e 74 20 6e inside a mount n
97d0: 61 6d 65 73 70 61 63 65 20 68 6f 6c 64 69 6e 67 amespace holding
97e0: 20 6f 6e 6c 79 20 69 74 73 20 72 6f 6f 74 2c 20 only its root,
97f0: 69 74 73 20 68 6f 6d 65 73 0a 20 20 20 20 61 6e its homes. an
9800: 64 20 74 68 65 20 73 79 73 74 65 6d 27 73 20 72 d the system's r
9810: 65 61 64 2d 6f 6e 6c 79 20 66 69 6c 65 73 3b 0a ead-only files;.
9820: 20 20 2d 20 69 74 20 6b 65 65 70 73 20 74 68 65 - it keeps the
9830: 20 68 6f 73 74 27 73 20 70 72 6f 63 65 73 73 20 host's process
9840: 6e 61 6d 65 73 70 61 63 65 2c 20 73 6f 20 77 61 namespace, so wa
9850: 74 63 68 65 72 73 20 6f 75 74 6c 69 76 65 20 61 tchers outlive a
9860: 20 72 65 73 74 61 72 74 2e 0a 0a 23 23 20 33 2e restart...## 3.
9870: 20 44 6f 63 75 6d 65 6e 74 73 0a 0a 2d 20 60 64 Documents..- `d
9880: 6f 63 73 2f 69 6e 74 65 72 66 61 63 65 73 2e 6d ocs/interfaces.m
9890: 64 60 3a 0a 20 20 2d 20 74 68 65 20 60 72 65 63 d`:. - the `rec
98a0: 65 69 70 74 60 20 72 6f 77 20 73 61 79 73 20 74 eipt` row says t
98b0: 68 65 20 77 65 62 20 70 61 67 65 27 73 20 60 72 he web page's `r
98c0: 65 63 65 69 70 74 60 20 72 65 6c 61 79 73 20 74 eceipt` relays t
98d0: 6f 20 74 68 65 20 72 65 63 65 69 70 74 0a 20 20 o the receipt.
98e0: 20 20 73 65 72 76 69 63 65 2c 20 62 79 20 74 68 service, by th
98f0: 65 20 74 77 6f 20 6c 69 6e 65 73 20 61 62 6f 76 e two lines abov
9900: 65 2c 20 67 69 76 65 6e 20 60 2d 2d 72 65 63 65 e, given `--rece
9910: 69 70 74 2d 66 64 60 3b 0a 20 20 2d 20 74 68 65 ipt-fd`;. - the
9920: 20 60 6d 69 67 72 61 74 65 60 20 72 6f 77 20 6e `migrate` row n
9930: 61 6d 65 73 20 74 68 65 20 75 6e 69 74 27 73 20 ames the unit's
9940: 60 55 73 65 72 3d 60 20 61 6e 64 20 6c 61 75 6e `User=` and laun
9950: 63 68 65 72 2e 0a 20 20 45 61 63 68 20 6e 61 6d cher.. Each nam
9960: 65 73 20 74 68 65 20 73 70 65 63 73 2e 0a 2d 20 es the specs..-
9970: 60 64 6f 63 73 2f 6d 69 67 72 61 74 65 2e 6d 64 `docs/migrate.md
9980: 60 3a 0a 20 20 2d 20 74 68 65 20 61 64 6d 69 6e `:. - the admin
9990: 20 6d 61 6b 65 73 20 74 68 65 20 61 63 63 6f 75 makes the accou
99a0: 6e 74 20 61 6e 64 20 6d 6f 76 65 73 20 74 68 65 nt and moves the
99b0: 20 43 6f 64 65 78 20 61 6e 64 20 43 6c 61 75 64 Codex and Claud
99c0: 65 20 68 6f 6d 65 73 0a 20 20 20 20 75 6e 64 65 e homes. unde
99d0: 72 20 60 2f 68 6f 6d 65 2f 6f 63 78 60 3b 0a 20 r `/home/ocx`;.
99e0: 20 2d 20 74 68 65 79 20 60 63 68 6f 77 6e 20 2d - they `chown -
99f0: 52 60 20 74 68 65 20 64 61 65 6d 6f 6e 27 73 20 R` the daemon's
9a00: 72 6f 6f 74 20 74 6f 20 69 74 20 61 66 74 65 72 root to it after
9a10: 20 60 6d 69 67 72 61 74 65 60 3b 0a 20 20 2d 20 `migrate`;. -
9a20: 74 68 65 79 20 62 75 69 6c 64 20 60 73 74 61 72 they build `star
9a30: 74 2d 6f 63 78 60 20 61 6e 64 20 60 72 65 63 65 t-ocx` and `rece
9a40: 69 70 74 73 60 20 69 6e 20 74 68 65 20 6d 61 69 ipts` in the mai
9a50: 6e 74 61 69 6e 65 72 27 73 20 63 68 65 63 6b 6f ntainer's checko
9a60: 75 74 0a 20 20 20 20 61 6e 64 20 69 6e 73 74 61 ut. and insta
9a70: 6c 6c 20 62 6f 74 68 20 72 6f 6f 74 2d 6f 77 6e ll both root-own
9a80: 65 64 3b 0a 20 20 2d 20 74 68 65 79 20 73 74 61 ed;. - they sta
9a90: 72 74 20 74 68 65 20 72 65 63 65 69 70 74 20 73 rt the receipt s
9aa0: 65 72 76 69 63 65 27 73 20 75 6e 69 74 20 28 69 ervice's unit (i
9ab0: 74 73 20 74 65 78 74 20 77 72 69 74 74 65 6e 20 ts text written
9ac0: 69 6e 20 74 68 65 0a 20 20 20 20 67 75 69 64 65 in the. guide
9ad0: 29 2c 20 72 75 6e 6e 69 6e 67 20 60 53 54 41 52 ), running `STAR
9ae0: 54 5f 4f 43 58 20 72 65 63 65 69 70 74 73 60 20 T_OCX receipts`
9af0: 61 73 20 74 68 65 20 61 63 63 6f 75 6e 74 20 46 as the account F
9b00: 6f 73 73 69 6c 20 72 75 6e 73 20 61 73 2e 0a 2d ossil runs as..-
9b10: 20 60 48 49 53 54 4f 52 59 2e 6d 64 60 3a 20 64 `HISTORY.md`: d
9b20: 65 63 69 73 69 6f 6e 20 31 32 37 2c 20 77 69 74 ecision 127, wit
9b30: 68 20 74 68 65 20 6d 61 69 6e 74 61 69 6e 65 72 h the maintainer
9b40: 27 73 20 77 6f 72 64 73 20 71 75 6f 74 65 64 20 's words quoted
9b50: 65 78 61 63 74 6c 79 2e 0a 20 20 54 61 6b 65 20 exactly.. Take
9b60: 74 68 65 6d 20 66 72 6f 6d 20 60 2e 2e 2f 77 6f them from `../wo
9b70: 72 6b 2f 73 74 61 67 65 41 2d 71 75 6f 74 65 73 rk/stageA-quotes
9b80: 2e 74 78 74 60 2e 20 54 68 65 6e 20 74 68 65 20 .txt`. Then the
9b90: 61 67 65 6e 74 27 73 20 73 75 6d 6d 61 72 79 2c agent's summary,
9ba0: 0a 20 20 6d 61 72 6b 65 64 20 61 73 20 74 68 65 . marked as the
9bb0: 20 61 67 65 6e 74 27 73 20 77 6f 72 64 73 3a 20 agent's words:
9bc0: 74 68 65 20 72 65 63 65 69 70 74 20 73 65 72 76 the receipt serv
9bd0: 69 63 65 2c 20 74 68 65 20 6c 61 75 6e 63 68 65 ice, the launche
9be0: 72 20 61 6e 64 20 69 74 73 0a 20 20 74 68 72 65 r and its. thre
9bf0: 65 20 6d 6f 64 65 73 2c 20 74 68 65 20 64 61 65 e modes, the dae
9c00: 6d 6f 6e 27 73 20 61 63 63 6f 75 6e 74 20 61 6e mon's account an
9c10: 64 20 6e 61 6d 65 73 70 61 63 65 2c 20 61 6e 64 d namespace, and
9c20: 20 74 68 65 20 74 65 6d 70 6f 72 61 72 79 0a 20 the temporary.
9c30: 20 70 61 73 73 74 68 72 6f 75 67 68 20 28 45 36 passthrough (E6
9c40: 29 2e 0a 2d 20 60 47 4c 4f 53 53 41 52 59 2e 6d )..- `GLOSSARY.m
9c50: 64 60 3a 20 74 77 6f 20 65 6e 74 72 69 65 73 2e d`: two entries.
9c60: 0a 20 20 2d 20 2a 2a 52 65 63 65 69 70 74 20 73 . - **Receipt s
9c70: 65 72 76 69 63 65 3a 2a 2a 20 74 68 65 20 6d 61 ervice:** the ma
9c80: 69 6e 74 61 69 6e 65 72 27 73 20 73 6d 61 6c 6c intainer's small
9c90: 20 72 65 61 64 2d 6f 6e 6c 79 20 70 72 6f 67 72 read-only progr
9ca0: 61 6d 20 74 68 61 74 0a 20 20 20 20 61 6e 73 77 am that. answ
9cb0: 65 72 73 20 77 68 6f 20 73 65 6e 74 20 61 6e 20 ers who sent an
9cc0: 61 72 74 69 66 61 63 74 20 66 72 6f 6d 20 74 68 artifact from th
9cd0: 65 20 73 65 72 76 65 64 20 72 65 70 6f 73 69 74 e served reposit
9ce0: 6f 72 69 65 73 2e 0a 20 20 2d 20 2a 2a 4c 61 75 ories.. - **Lau
9cf0: 6e 63 68 65 72 3a 2a 2a 20 60 73 63 72 69 70 74 ncher:** `script
9d00: 73 2f 73 74 61 72 74 2d 6f 63 78 2e 63 72 60 2c s/start-ocx.cr`,
9d10: 20 77 68 69 63 68 20 73 74 61 72 74 73 20 74 68 which starts th
9d20: 65 20 43 47 49 2c 20 74 68 65 0a 20 20 20 20 72 e CGI, the. r
9d30: 65 63 65 69 70 74 20 73 65 72 76 69 63 65 20 61 eceipt service a
9d40: 6e 64 20 74 68 65 20 64 61 65 6d 6f 6e 2c 20 65 nd the daemon, e
9d50: 61 63 68 20 69 6e 20 61 20 66 69 78 65 64 20 73 ach in a fixed s
9d60: 61 6e 64 62 6f 78 2e 0a 0a 23 23 20 44 6f 6e 65 andbox...## Done
9d70: 20 77 68 65 6e 0a 0a 2d 20 54 68 65 20 67 61 74 when..- The gat
9d80: 65 20 70 61 73 73 65 73 3a 20 60 63 72 79 73 74 e passes: `cryst
9d90: 61 6c 20 72 75 6e 20 63 69 2e 63 72 60 2e 20 59 al run ci.cr`. Y
9da0: 6f 75 20 63 61 6e 6e 6f 74 20 72 75 6e 20 69 74 ou cannot run it
9db0: 73 20 6e 65 74 77 6f 72 6b 20 73 70 65 63 73 0a s network specs.
9dc0: 20 20 69 6e 20 79 6f 75 72 20 73 61 6e 64 62 6f in your sandbo
9dd0: 78 2c 20 73 6f 20 72 75 6e 20 61 74 20 6c 65 61 x, so run at lea
9de0: 73 74 20 60 63 72 79 73 74 61 6c 20 73 70 65 63 st `crystal spec
9df0: 60 20 6f 6e 20 74 68 65 20 73 70 65 63 20 66 69 ` on the spec fi
9e00: 6c 65 73 20 79 6f 75 0a 20 20 74 6f 75 63 68 65 les you. touche
9e10: 64 2c 20 70 6c 75 73 20 60 73 70 65 63 2f 67 75 d, plus `spec/gu
9e20: 61 72 64 73 60 2e 0a 2d 20 50 72 69 6e 74 20 74 ards`..- Print t
9e30: 68 65 20 66 75 6c 6c 20 64 69 66 66 2e 0a 00 00 he full diff....
9e40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9e50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9e60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9e70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9e90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9ea0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9eb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9ec0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9ed0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9ee0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9ef0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9f10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9f20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9f30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9f40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9f50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9f60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9f70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9f90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9fa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a000: 73 74 61 67 65 41 2d 72 65 63 6f 72 64 2f 73 74 stageA-record/st
a010: 61 72 74 2d 6f 63 78 2e 63 72 00 00 00 00 00 00 art-ocx.cr......
a020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a060: 00 00 00 00 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000
a070: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
a080: 30 30 32 31 35 35 31 00 31 35 32 37 30 34 37 36 0021551.15270476
a090: 32 30 35 00 30 31 34 35 32 32 00 20 30 00 00 00 205.014522. 0...
a0a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a0b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a0c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a0d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a0e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a0f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a100: 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
a110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a120: 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
a130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a1a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a1b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a1c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a1d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a1e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a1f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a200: 23 20 41 67 65 6e 74 73 3a 20 64 6f 20 6e 6f 74 # Agents: do not
a210: 20 63 68 61 6e 67 65 20 74 68 69 73 20 66 69 6c change this fil
a220: 65 20 6f 6e 20 61 6e 79 20 62 72 61 6e 63 68 20 e on any branch
a230: 77 69 74 68 6f 75 74 20 74 68 65 20 6d 61 69 6e without the main
a240: 74 61 69 6e 65 72 27 73 20 65 78 70 6c 69 63 69 tainer's explici
a250: 74 20 61 70 70 72 6f 76 61 6c 20 6f 6e 20 74 68 t approval on th
a260: 65 20 72 65 63 6f 72 64 2e 0a 23 20 53 65 6c 66 e record..# Self
a270: 2d 63 6f 6e 74 61 69 6e 65 64 20 68 6f 73 74 20 -contained host
a280: 6c 61 75 6e 63 68 65 72 3a 20 6f 6e 6c 79 20 74 launcher: only t
a290: 68 65 20 70 61 74 68 73 20 62 65 6c 6f 77 2c 20 he paths below,
a2a0: 72 65 6c 65 61 73 65 20 6c 69 6e 6b 73 2c 20 2f release links, /
a2b0: 70 72 6f 63 2f 73 65 6c 66 2f 66 64 2c 0a 23 20 proc/self/fd,.#
a2c0: 65 78 65 63 75 74 61 62 6c 65 20 6c 6f 63 61 74 executable locat
a2d0: 69 6f 6e 2c 20 65 78 69 73 74 69 6e 67 20 68 6f ion, existing ho
a2e0: 6d 65 20 70 61 74 68 73 20 61 6e 64 20 46 6f 73 me paths and Fos
a2f0: 73 69 6c 27 73 20 43 47 49 20 65 6e 76 69 72 6f sil's CGI enviro
a300: 6e 6d 65 6e 74 20 61 72 65 20 72 65 61 64 2e 0a nment are read..
a310: 23 20 42 75 69 6c 64 20 62 65 73 69 64 65 20 72 # Build beside r
a320: 65 63 65 69 70 74 73 20 77 69 74 68 20 60 73 68 eceipts with `sh
a330: 61 72 64 73 20 62 75 69 6c 64 20 73 74 61 72 74 ards build start
a340: 2d 6f 63 78 20 72 65 63 65 69 70 74 73 60 20 69 -ocx receipts` i
a350: 6e 20 61 20 63 68 65 63 6b 6f 75 74 2e 0a 72 65 n a checkout..re
a360: 71 75 69 72 65 20 22 6a 73 6f 6e 22 0a 72 65 71 quire "json".req
a370: 75 69 72 65 20 22 73 6f 63 6b 65 74 22 0a 0a 6c uire "socket"..l
a380: 69 62 20 4c 69 62 43 0a 20 20 66 75 6e 20 65 78 ib LibC. fun ex
a390: 65 63 76 28 70 61 74 68 20 3a 20 43 68 61 72 2a ecv(path : Char*
a3a0: 2c 20 61 72 67 76 20 3a 20 43 68 61 72 2a 2a 29 , argv : Char**)
a3b0: 20 3a 20 49 6e 74 0a 65 6e 64 0a 0a 6d 6f 64 75 : Int.end..modu
a3c0: 6c 65 20 53 74 61 72 74 4f 43 58 0a 20 20 4c 49 le StartOCX. LI
a3d0: 56 45 5f 48 4f 53 54 20 20 20 20 20 20 20 20 20 VE_HOST
a3e0: 3d 20 22 69 70 2d 31 37 32 2d 33 31 2d 31 37 2d = "ip-172-31-17-
a3f0: 31 37 37 2e 75 73 2d 77 65 73 74 2d 32 2e 63 6f 177.us-west-2.co
a400: 6d 70 75 74 65 2e 69 6e 74 65 72 6e 61 6c 22 0a mpute.internal".
a410: 20 20 4c 49 56 45 5f 52 45 50 4f 53 49 54 4f 52 LIVE_REPOSITOR
a420: 49 45 53 20 3d 20 22 2f 76 61 72 2f 6c 69 62 2f IES = "/var/lib/
a430: 66 6f 73 73 69 6c 22 0a 20 20 4c 49 56 45 5f 53 fossil". LIVE_S
a440: 4f 43 4b 45 54 5f 44 49 52 20 20 20 3d 20 22 2f OCKET_DIR = "/
a450: 72 75 6e 2f 6f 63 78 22 0a 20 20 4c 49 56 45 5f run/ocx". LIVE_
a460: 52 45 4c 45 41 53 45 20 20 20 20 20 20 3d 20 22 RELEASE = "
a470: 2f 76 61 72 2f 6c 69 62 2f 6f 63 78 2f 72 65 6c /var/lib/ocx/rel
a480: 65 61 73 65 32 22 0a 20 20 4c 49 56 45 5f 44 41 ease2". LIVE_DA
a490: 45 4d 4f 4e 20 20 20 20 20 20 20 3d 20 22 2f 76 EMON = "/v
a4a0: 61 72 2f 6c 69 62 2f 6f 63 78 2f 61 67 65 6e 74 ar/lib/ocx/agent
a4b0: 73 2d 64 61 65 6d 6f 6e 22 0a 20 20 4c 49 56 45 s-daemon". LIVE
a4c0: 5f 48 4f 4d 45 20 20 20 20 20 20 20 20 20 3d 20 _HOME =
a4d0: 22 2f 68 6f 6d 65 2f 6f 63 78 22 0a 20 20 43 47 "/home/ocx". CG
a4e0: 49 5f 46 49 45 4c 44 53 20 20 20 20 20 20 20 20 I_FIELDS
a4f0: 3d 20 25 77 28 52 45 51 55 45 53 54 5f 4d 45 54 = %w(REQUEST_MET
a500: 48 4f 44 20 51 55 45 52 59 5f 53 54 52 49 4e 47 HOD QUERY_STRING
a510: 20 50 41 54 48 5f 49 4e 46 4f 20 43 4f 4e 54 45 PATH_INFO CONTE
a520: 4e 54 5f 4c 45 4e 47 54 48 20 43 4f 4e 54 45 4e NT_LENGTH CONTEN
a530: 54 5f 54 59 50 45 20 48 54 54 50 53 20 48 54 54 T_TYPE HTTPS HTT
a540: 50 5f 48 4f 53 54 20 48 54 54 50 5f 52 45 46 45 P_HOST HTTP_REFE
a550: 52 45 52 20 46 4f 53 53 49 4c 5f 55 53 45 52 20 RER FOSSIL_USER
a560: 46 4f 53 53 49 4c 5f 43 41 50 41 42 49 4c 49 54 FOSSIL_CAPABILIT
a570: 49 45 53 20 46 4f 53 53 49 4c 5f 55 52 49 29 0a IES FOSSIL_URI).
a580: 20 20 4c 49 42 52 41 52 49 45 53 20 20 20 20 20 LIBRARIES
a590: 20 20 20 20 3d 20 25 77 28 2f 6c 69 62 20 2f 6c = %w(/lib /l
a5a0: 69 62 36 34 29 0a 20 20 44 41 45 4d 4f 4e 5f 53 ib64). DAEMON_S
a5b0: 59 53 54 45 4d 20 20 20 20 20 3d 20 25 77 28 2f YSTEM = %w(/
a5c0: 6c 69 62 20 2f 6c 69 62 36 34 20 2f 62 69 6e 20 lib /lib64 /bin
a5d0: 2f 73 62 69 6e 20 2f 65 74 63 2f 73 73 6c 20 2f /sbin /etc/ssl /
a5e0: 65 74 63 2f 70 6b 69 20 2f 65 74 63 2f 72 65 73 etc/pki /etc/res
a5f0: 6f 6c 76 2e 63 6f 6e 66 20 2f 65 74 63 2f 68 6f olv.conf /etc/ho
a600: 73 74 73 20 2f 65 74 63 2f 6e 73 73 77 69 74 63 sts /etc/nsswitc
a610: 68 2e 63 6f 6e 66 20 2f 65 74 63 2f 70 61 73 73 h.conf /etc/pass
a620: 77 64 20 2f 65 74 63 2f 67 72 6f 75 70 29 0a 0a wd /etc/group)..
a630: 20 20 72 65 63 6f 72 64 20 50 61 74 68 73 2c 20 record Paths,
a640: 72 65 70 6f 73 69 74 6f 72 69 65 73 20 3a 20 53 repositories : S
a650: 74 72 69 6e 67 2c 20 73 6f 63 6b 65 74 5f 64 69 tring, socket_di
a660: 72 20 3a 20 53 74 72 69 6e 67 2c 20 72 65 6c 65 r : String, rele
a670: 61 73 65 20 3a 20 53 74 72 69 6e 67 2c 20 64 61 ase : String, da
a680: 65 6d 6f 6e 20 3a 20 53 74 72 69 6e 67 2c 20 68 emon : String, h
a690: 6f 6d 65 20 3a 20 53 74 72 69 6e 67 2c 20 68 6f ome : String, ho
a6a0: 6d 65 73 20 3a 20 41 72 72 61 79 28 54 75 70 6c mes : Array(Tupl
a6b0: 65 28 53 74 72 69 6e 67 2c 20 42 6f 6f 6c 29 29 e(String, Bool))
a6c0: 20 64 6f 0a 20 20 20 20 64 65 66 20 73 6f 63 6b do. def sock
a6d0: 65 74 20 3a 20 53 74 72 69 6e 67 0a 20 20 20 20 et : String.
a6e0: 20 20 46 69 6c 65 2e 6a 6f 69 6e 28 73 6f 63 6b File.join(sock
a6f0: 65 74 5f 64 69 72 2c 20 22 72 65 63 65 69 70 74 et_dir, "receipt
a700: 73 2e 73 6f 63 6b 22 29 0a 20 20 20 20 65 6e 64 s.sock"). end
a710: 0a 20 20 65 6e 64 0a 0a 20 20 64 65 66 20 73 65 . end.. def se
a720: 6c 66 2e 70 61 74 68 73 28 73 63 72 61 74 63 68 lf.paths(scratch
a730: 20 3a 20 53 74 72 69 6e 67 3f 2c 20 68 6f 73 74 : String?, host
a740: 20 3a 20 53 74 72 69 6e 67 29 20 3a 20 50 61 74 : String) : Pat
a750: 68 73 0a 20 20 20 20 69 66 20 73 63 72 61 74 63 hs. if scratc
a760: 68 0a 20 20 20 20 20 20 72 61 69 73 65 20 41 72 h. raise Ar
a770: 67 75 6d 65 6e 74 45 72 72 6f 72 2e 6e 65 77 28 gumentError.new(
a780: 22 73 63 72 61 74 63 68 20 64 69 72 65 63 74 6f "scratch directo
a790: 72 79 20 6d 75 73 74 20 62 65 20 61 62 73 6f 6c ry must be absol
a7a0: 75 74 65 22 29 20 75 6e 6c 65 73 73 20 73 63 72 ute") unless scr
a7b0: 61 74 63 68 2e 73 74 61 72 74 73 5f 77 69 74 68 atch.starts_with
a7c0: 3f 28 22 2f 22 29 0a 20 20 20 20 20 20 72 6f 6f ?("/"). roo
a7d0: 74 20 3d 20 46 69 6c 65 2e 65 78 70 61 6e 64 5f t = File.expand_
a7e0: 70 61 74 68 28 73 63 72 61 74 63 68 29 0a 20 20 path(scratch).
a7f0: 20 20 20 20 68 6f 6d 65 20 3d 20 46 69 6c 65 2e home = File.
a800: 6a 6f 69 6e 28 72 6f 6f 74 2c 20 22 68 6f 6d 65 join(root, "home
a810: 22 29 0a 20 20 20 20 20 20 50 61 74 68 73 2e 6e "). Paths.n
a820: 65 77 28 46 69 6c 65 2e 6a 6f 69 6e 28 72 6f 6f ew(File.join(roo
a830: 74 2c 20 22 66 6f 73 73 69 6c 22 29 2c 20 46 69 t, "fossil"), Fi
a840: 6c 65 2e 6a 6f 69 6e 28 72 6f 6f 74 2c 20 22 72 le.join(root, "r
a850: 75 6e 22 29 2c 20 46 69 6c 65 2e 6a 6f 69 6e 28 un"), File.join(
a860: 72 6f 6f 74 2c 20 22 72 65 6c 65 61 73 65 22 29 root, "release")
a870: 2c 20 46 69 6c 65 2e 6a 6f 69 6e 28 72 6f 6f 74 , File.join(root
a880: 2c 20 22 64 61 65 6d 6f 6e 22 29 2c 20 68 6f 6d , "daemon"), hom
a890: 65 2c 20 5b 7b 46 69 6c 65 2e 6a 6f 69 6e 28 68 e, [{File.join(h
a8a0: 6f 6d 65 2c 20 22 2e 63 6f 64 65 78 22 29 2c 20 ome, ".codex"),
a8b0: 74 72 75 65 7d 5d 29 0a 20 20 20 20 65 6c 73 69 true}]). elsi
a8c0: 66 20 68 6f 73 74 20 3d 3d 20 4c 49 56 45 5f 48 f host == LIVE_H
a8d0: 4f 53 54 0a 20 20 20 20 20 20 50 61 74 68 73 2e OST. Paths.
a8e0: 6e 65 77 28 4c 49 56 45 5f 52 45 50 4f 53 49 54 new(LIVE_REPOSIT
a8f0: 4f 52 49 45 53 2c 20 4c 49 56 45 5f 53 4f 43 4b ORIES, LIVE_SOCK
a900: 45 54 5f 44 49 52 2c 20 4c 49 56 45 5f 52 45 4c ET_DIR, LIVE_REL
a910: 45 41 53 45 2c 20 4c 49 56 45 5f 44 41 45 4d 4f EASE, LIVE_DAEMO
a920: 4e 2c 20 4c 49 56 45 5f 48 4f 4d 45 2c 0a 20 20 N, LIVE_HOME,.
a930: 20 20 20 20 20 20 5b 7b 22 2f 68 6f 6d 65 2f 6f [{"/home/o
a940: 63 78 2f 2e 63 6f 64 65 78 22 2c 20 74 72 75 65 cx/.codex", true
a950: 7d 2c 20 7b 22 2f 68 6f 6d 65 2f 6f 63 78 2f 2e }, {"/home/ocx/.
a960: 63 6c 61 75 64 65 22 2c 20 74 72 75 65 7d 2c 20 claude", true},
a970: 7b 22 2f 68 6f 6d 65 2f 6f 63 78 2f 2e 63 6c 61 {"/home/ocx/.cla
a980: 75 64 65 2e 6a 73 6f 6e 22 2c 20 74 72 75 65 7d ude.json", true}
a990: 2c 20 7b 22 2f 68 6f 6d 65 2f 6f 63 78 2f 2e 6c , {"/home/ocx/.l
a9a0: 6f 63 61 6c 22 2c 20 66 61 6c 73 65 7d 5d 29 0a ocal", false}]).
a9b0: 20 20 20 20 65 6c 73 65 0a 20 20 20 20 20 20 72 else. r
a9c0: 61 69 73 65 20 41 72 67 75 6d 65 6e 74 45 72 72 aise ArgumentErr
a9d0: 6f 72 2e 6e 65 77 28 22 75 6e 6b 6e 6f 77 6e 20 or.new("unknown
a9e0: 68 6f 73 74 3b 20 75 73 65 20 2d 2d 73 63 72 61 host; use --scra
a9f0: 74 63 68 20 44 49 52 22 29 0a 20 20 20 20 65 6e tch DIR"). en
aa00: 64 0a 20 20 65 6e 64 0a 0a 20 20 23 20 54 68 65 d. end.. # The
aa10: 73 65 20 74 68 72 65 65 20 62 75 69 6c 64 65 72 se three builder
aa20: 73 20 72 65 61 64 20 6e 6f 74 68 69 6e 67 3a 20 s read nothing:
aa30: 74 68 65 69 72 20 66 75 6c 6c 20 61 72 67 75 6d their full argum
aa40: 65 6e 74 20 6c 69 73 74 73 20 63 61 6e 20 62 65 ent lists can be
aa50: 20 69 6e 73 70 65 63 74 65 64 2e 0a 20 20 64 65 inspected.. de
aa60: 66 20 73 65 6c 66 2e 63 67 69 5f 61 72 67 73 28 f self.cgi_args(
aa70: 72 65 6c 65 61 73 65 20 3a 20 53 74 72 69 6e 67 release : String
aa80: 2c 20 72 65 70 6f 73 69 74 6f 72 79 20 3a 20 53 , repository : S
aa90: 74 72 69 6e 67 2c 20 65 6e 76 69 72 6f 6e 6d 65 tring, environme
aaa0: 6e 74 20 3a 20 48 61 73 68 28 53 74 72 69 6e 67 nt : Hash(String
aab0: 2c 20 53 74 72 69 6e 67 29 29 20 3a 20 41 72 72 , String)) : Arr
aac0: 61 79 28 53 74 72 69 6e 67 29 0a 20 20 20 20 61 ay(String). a
aad0: 72 67 73 20 3d 20 25 77 28 2d 2d 75 6e 73 68 61 rgs = %w(--unsha
aae0: 72 65 2d 61 6c 6c 20 2d 2d 64 69 65 2d 77 69 74 re-all --die-wit
aaf0: 68 2d 70 61 72 65 6e 74 20 2d 2d 6e 65 77 2d 73 h-parent --new-s
ab00: 65 73 73 69 6f 6e 20 2d 2d 63 6c 65 61 72 65 6e ession --clearen
ab10: 76 20 2d 2d 72 6f 2d 62 69 6e 64 20 2f 75 73 72 v --ro-bind /usr
ab20: 20 2f 75 73 72 29 0a 20 20 20 20 28 4c 49 42 52 /usr). (LIBR
ab30: 41 52 49 45 53 20 2b 20 5b 22 2f 62 69 6e 22 2c ARIES + ["/bin",
ab40: 20 22 2f 65 74 63 2f 70 61 73 73 77 64 22 5d 29 "/etc/passwd"])
ab50: 2e 65 61 63 68 20 7b 20 7c 70 61 74 68 7c 20 61 .each { |path| a
ab60: 72 67 73 2e 63 6f 6e 63 61 74 28 5b 22 2d 2d 72 rgs.concat(["--r
ab70: 6f 2d 62 69 6e 64 2d 74 72 79 22 2c 20 70 61 74 o-bind-try", pat
ab80: 68 2c 20 70 61 74 68 5d 29 20 7d 0a 20 20 20 20 h, path]) }.
ab90: 61 72 67 73 2e 63 6f 6e 63 61 74 28 5b 22 2d 2d args.concat(["--
aba0: 70 72 6f 63 22 2c 20 22 2f 70 72 6f 63 22 2c 20 proc", "/proc",
abb0: 22 2d 2d 64 65 76 22 2c 20 22 2f 64 65 76 22 2c "--dev", "/dev",
abc0: 20 22 2d 2d 74 6d 70 66 73 22 2c 20 22 2f 74 6d "--tmpfs", "/tm
abd0: 70 22 2c 20 22 2d 2d 72 6f 2d 62 69 6e 64 22 2c p", "--ro-bind",
abe0: 20 46 69 6c 65 2e 6a 6f 69 6e 28 72 65 6c 65 61 File.join(relea
abf0: 73 65 2c 20 22 6f 63 78 32 22 29 2c 20 22 2f 72 se, "ocx2"), "/r
ac00: 65 6c 65 61 73 65 2f 6f 63 78 32 2d 63 67 69 22 elease/ocx2-cgi"
ac10: 5d 29 0a 20 20 20 20 43 47 49 5f 46 49 45 4c 44 ]). CGI_FIELD
ac20: 53 2e 65 61 63 68 20 64 6f 20 7c 6b 65 79 7c 0a S.each do |key|.
ac30: 20 20 20 20 20 20 69 66 20 76 61 6c 75 65 20 3d if value =
ac40: 20 65 6e 76 69 72 6f 6e 6d 65 6e 74 5b 6b 65 79 environment[key
ac50: 5d 3f 0a 20 20 20 20 20 20 20 20 61 72 67 73 2e ]?. args.
ac60: 63 6f 6e 63 61 74 28 5b 22 2d 2d 73 65 74 65 6e concat(["--seten
ac70: 76 22 2c 20 6b 65 79 2c 20 76 61 6c 75 65 5d 29 v", key, value])
ac80: 0a 20 20 20 20 20 20 65 6e 64 0a 20 20 20 20 65 . end. e
ac90: 6e 64 0a 20 20 20 20 61 72 67 73 2e 63 6f 6e 63 nd. args.conc
aca0: 61 74 28 5b 22 2d 2d 73 65 74 65 6e 76 22 2c 20 at(["--setenv",
acb0: 22 46 4f 53 53 49 4c 5f 52 45 50 4f 53 49 54 4f "FOSSIL_REPOSITO
acc0: 52 59 22 2c 20 72 65 70 6f 73 69 74 6f 72 79 2c RY", repository,
acd0: 20 22 2d 2d 73 65 74 65 6e 76 22 2c 20 22 50 41 "--setenv", "PA
ace0: 54 48 22 2c 20 22 2f 75 73 72 2f 62 69 6e 22 2c TH", "/usr/bin",
acf0: 20 22 2f 72 65 6c 65 61 73 65 2f 6f 63 78 32 2d "/release/ocx2-
ad00: 63 67 69 22 2c 20 22 2d 2d 72 65 63 65 69 70 74 cgi", "--receipt
ad10: 2d 66 64 22 2c 20 22 33 22 5d 29 0a 20 20 65 6e -fd", "3"]). en
ad20: 64 0a 0a 20 20 64 65 66 20 73 65 6c 66 2e 72 65 d.. def self.re
ad30: 63 65 69 70 74 73 5f 61 72 67 73 28 70 61 74 68 ceipts_args(path
ad40: 73 20 3a 20 50 61 74 68 73 2c 20 65 78 65 63 75 s : Paths, execu
ad50: 74 61 62 6c 65 5f 64 69 72 20 3a 20 53 74 72 69 table_dir : Stri
ad60: 6e 67 29 20 3a 20 41 72 72 61 79 28 53 74 72 69 ng) : Array(Stri
ad70: 6e 67 29 0a 20 20 20 20 61 72 67 73 20 3d 20 25 ng). args = %
ad80: 77 28 2d 2d 75 6e 73 68 61 72 65 2d 61 6c 6c 20 w(--unshare-all
ad90: 2d 2d 64 69 65 2d 77 69 74 68 2d 70 61 72 65 6e --die-with-paren
ada0: 74 20 2d 2d 6e 65 77 2d 73 65 73 73 69 6f 6e 20 t --new-session
adb0: 2d 2d 63 61 70 2d 64 72 6f 70 20 41 4c 4c 20 2d --cap-drop ALL -
adc0: 2d 63 6c 65 61 72 65 6e 76 20 2d 2d 72 6f 2d 62 -clearenv --ro-b
add0: 69 6e 64 20 2f 75 73 72 20 2f 75 73 72 29 0a 20 ind /usr /usr).
ade0: 20 20 20 4c 49 42 52 41 52 49 45 53 2e 65 61 63 LIBRARIES.eac
adf0: 68 20 7b 20 7c 70 61 74 68 7c 20 61 72 67 73 2e h { |path| args.
ae00: 63 6f 6e 63 61 74 28 5b 22 2d 2d 72 6f 2d 62 69 concat(["--ro-bi
ae10: 6e 64 2d 74 72 79 22 2c 20 70 61 74 68 2c 20 70 nd-try", path, p
ae20: 61 74 68 5d 29 20 7d 0a 20 20 20 20 61 72 67 73 ath]) }. args
ae30: 2e 63 6f 6e 63 61 74 28 5b 22 2d 2d 64 65 76 22 .concat(["--dev"
ae40: 2c 20 22 2f 64 65 76 22 2c 20 22 2d 2d 74 6d 70 , "/dev", "--tmp
ae50: 66 73 22 2c 20 22 2f 74 6d 70 22 2c 20 22 2d 2d fs", "/tmp", "--
ae60: 72 6f 2d 62 69 6e 64 22 2c 20 70 61 74 68 73 2e ro-bind", paths.
ae70: 72 65 70 6f 73 69 74 6f 72 69 65 73 2c 20 70 61 repositories, pa
ae80: 74 68 73 2e 72 65 70 6f 73 69 74 6f 72 69 65 73 ths.repositories
ae90: 2c 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ,.
aea0: 20 20 20 22 2d 2d 62 69 6e 64 22 2c 20 70 61 74 "--bind", pat
aeb0: 68 73 2e 73 6f 63 6b 65 74 5f 64 69 72 2c 20 70 hs.socket_dir, p
aec0: 61 74 68 73 2e 73 6f 63 6b 65 74 5f 64 69 72 2c aths.socket_dir,
aed0: 20 22 2d 2d 72 6f 2d 62 69 6e 64 22 2c 20 46 69 "--ro-bind", Fi
aee0: 6c 65 2e 6a 6f 69 6e 28 65 78 65 63 75 74 61 62 le.join(executab
aef0: 6c 65 5f 64 69 72 2c 20 22 72 65 63 65 69 70 74 le_dir, "receipt
af00: 73 22 29 2c 20 22 2f 72 65 63 65 69 70 74 73 22 s"), "/receipts"
af10: 2c 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ,.
af20: 20 20 20 22 2f 72 65 63 65 69 70 74 73 22 2c 20 "/receipts",
af30: 70 61 74 68 73 2e 73 6f 63 6b 65 74 2c 20 70 61 paths.socket, pa
af40: 74 68 73 2e 72 65 70 6f 73 69 74 6f 72 69 65 73 ths.repositories
af50: 5d 29 0a 20 20 65 6e 64 0a 0a 20 20 64 65 66 20 ]). end.. def
af60: 73 65 6c 66 2e 64 61 65 6d 6f 6e 5f 61 72 67 73 self.daemon_args
af70: 28 70 61 74 68 73 20 3a 20 50 61 74 68 73 2c 20 (paths : Paths,
af80: 68 6f 6d 65 73 20 3a 20 41 72 72 61 79 28 54 75 homes : Array(Tu
af90: 70 6c 65 28 53 74 72 69 6e 67 2c 20 42 6f 6f 6c ple(String, Bool
afa0: 29 29 29 20 3a 20 41 72 72 61 79 28 53 74 72 69 ))) : Array(Stri
afb0: 6e 67 29 0a 20 20 20 20 61 72 67 73 20 3d 20 5b ng). args = [
afc0: 22 2d 2d 75 6e 73 68 61 72 65 2d 75 73 65 72 22 "--unshare-user"
afd0: 2c 20 22 2d 2d 75 6e 73 68 61 72 65 2d 69 70 63 , "--unshare-ipc
afe0: 22 2c 20 22 2d 2d 75 6e 73 68 61 72 65 2d 75 74 ", "--unshare-ut
aff0: 73 22 2c 20 22 2d 2d 63 6c 65 61 72 65 6e 76 22 s", "--clearenv"
b000: 2c 20 22 2d 2d 73 65 74 65 6e 76 22 2c 20 22 48 , "--setenv", "H
b010: 4f 4d 45 22 2c 20 70 61 74 68 73 2e 68 6f 6d 65 OME", paths.home
b020: 2c 0a 20 20 20 20 20 20 20 20 20 20 20 20 22 2d ,. "-
b030: 2d 73 65 74 65 6e 76 22 2c 20 22 50 41 54 48 22 -setenv", "PATH"
b040: 2c 20 22 2f 75 73 72 2f 62 69 6e 3a 2f 62 69 6e , "/usr/bin:/bin
b050: 22 2c 20 22 2d 2d 72 6f 2d 62 69 6e 64 22 2c 20 ", "--ro-bind",
b060: 22 2f 75 73 72 22 2c 20 22 2f 75 73 72 22 5d 0a "/usr", "/usr"].
b070: 20 20 20 20 44 41 45 4d 4f 4e 5f 53 59 53 54 45 DAEMON_SYSTE
b080: 4d 2e 65 61 63 68 20 7b 20 7c 70 61 74 68 7c 20 M.each { |path|
b090: 61 72 67 73 2e 63 6f 6e 63 61 74 28 5b 22 2d 2d args.concat(["--
b0a0: 72 6f 2d 62 69 6e 64 2d 74 72 79 22 2c 20 70 61 ro-bind-try", pa
b0b0: 74 68 2c 20 70 61 74 68 5d 29 20 7d 0a 20 20 20 th, path]) }.
b0c0: 20 61 72 67 73 2e 63 6f 6e 63 61 74 28 5b 22 2d args.concat(["-
b0d0: 2d 70 72 6f 63 22 2c 20 22 2f 70 72 6f 63 22 2c -proc", "/proc",
b0e0: 20 22 2d 2d 64 65 76 22 2c 20 22 2f 64 65 76 22 "--dev", "/dev"
b0f0: 2c 20 22 2d 2d 74 6d 70 66 73 22 2c 20 22 2f 74 , "--tmpfs", "/t
b100: 6d 70 22 2c 20 22 2d 2d 74 6d 70 66 73 22 2c 20 mp", "--tmpfs",
b110: 70 61 74 68 73 2e 68 6f 6d 65 5d 29 0a 20 20 20 paths.home]).
b120: 20 68 6f 6d 65 73 2e 65 61 63 68 20 7b 20 7c 70 homes.each { |p
b130: 61 74 68 2c 20 77 72 69 74 61 62 6c 65 7c 20 61 ath, writable| a
b140: 72 67 73 2e 63 6f 6e 63 61 74 28 5b 77 72 69 74 rgs.concat([writ
b150: 61 62 6c 65 20 3f 20 22 2d 2d 62 69 6e 64 2d 74 able ? "--bind-t
b160: 72 79 22 20 3a 20 22 2d 2d 72 6f 2d 62 69 6e 64 ry" : "--ro-bind
b170: 2d 74 72 79 22 2c 20 70 61 74 68 2c 20 70 61 74 -try", path, pat
b180: 68 5d 29 20 7d 0a 20 20 20 20 61 72 67 73 2e 63 h]) }. args.c
b190: 6f 6e 63 61 74 28 5b 22 2d 2d 62 69 6e 64 22 2c oncat(["--bind",
b1a0: 20 70 61 74 68 73 2e 64 61 65 6d 6f 6e 2c 20 70 paths.daemon, p
b1b0: 61 74 68 73 2e 64 61 65 6d 6f 6e 2c 20 46 69 6c aths.daemon, Fil
b1c0: 65 2e 6a 6f 69 6e 28 70 61 74 68 73 2e 64 61 65 e.join(paths.dae
b1d0: 6d 6f 6e 2c 20 22 63 75 72 72 65 6e 74 22 2c 20 mon, "current",
b1e0: 22 6f 63 78 32 22 29 2c 20 22 64 61 65 6d 6f 6e "ocx2"), "daemon
b1f0: 22 2c 20 46 69 6c 65 2e 6a 6f 69 6e 28 70 61 74 ", File.join(pat
b200: 68 73 2e 64 61 65 6d 6f 6e 2c 20 22 6e 6f 64 65 hs.daemon, "node
b210: 22 2c 20 22 6e 6f 64 65 73 2e 6a 73 6f 6e 22 29 ", "nodes.json")
b220: 5d 29 0a 20 20 65 6e 64 0a 0a 20 20 23 20 52 65 ]). end.. # Re
b230: 73 6f 6c 76 65 20 65 78 69 73 74 69 6e 67 20 61 solve existing a
b240: 6e 63 65 73 74 6f 72 73 20 74 6f 6f 2c 20 73 6f ncestors too, so
b250: 20 61 6e 20 61 62 73 65 6e 74 20 6c 65 61 66 20 an absent leaf
b260: 63 61 6e 6e 6f 74 20 68 69 64 65 20 61 20 73 79 cannot hide a sy
b270: 6d 6c 69 6e 6b 2e 0a 20 20 64 65 66 20 73 65 6c mlink.. def sel
b280: 66 2e 72 65 61 6c 5f 62 6f 75 6e 64 28 70 61 74 f.real_bound(pat
b290: 68 20 3a 20 53 74 72 69 6e 67 29 20 3a 20 53 74 h : String) : St
b2a0: 72 69 6e 67 0a 20 20 20 20 72 65 74 75 72 6e 20 ring. return
b2b0: 46 69 6c 65 2e 72 65 61 6c 70 61 74 68 28 70 61 File.realpath(pa
b2c0: 74 68 29 20 69 66 20 46 69 6c 65 2e 65 78 69 73 th) if File.exis
b2d0: 74 73 3f 28 70 61 74 68 29 20 7c 7c 20 46 69 6c ts?(path) || Fil
b2e0: 65 2e 73 79 6d 6c 69 6e 6b 3f 28 70 61 74 68 29 e.symlink?(path)
b2f0: 0a 20 20 20 20 65 78 70 61 6e 64 65 64 20 3d 20 . expanded =
b300: 46 69 6c 65 2e 65 78 70 61 6e 64 5f 70 61 74 68 File.expand_path
b310: 28 70 61 74 68 29 0a 20 20 20 20 72 65 74 75 72 (path). retur
b320: 6e 20 65 78 70 61 6e 64 65 64 20 69 66 20 65 78 n expanded if ex
b330: 70 61 6e 64 65 64 20 3d 3d 20 22 2f 22 0a 20 20 panded == "/".
b340: 20 20 46 69 6c 65 2e 6a 6f 69 6e 28 72 65 61 6c File.join(real
b350: 5f 62 6f 75 6e 64 28 46 69 6c 65 2e 64 69 72 6e _bound(File.dirn
b360: 61 6d 65 28 65 78 70 61 6e 64 65 64 29 29 2c 20 ame(expanded)),
b370: 46 69 6c 65 2e 62 61 73 65 6e 61 6d 65 28 65 78 File.basename(ex
b380: 70 61 6e 64 65 64 29 29 0a 20 20 65 6e 64 0a 0a panded)). end..
b390: 20 20 64 65 66 20 73 65 6c 66 2e 67 75 61 72 64 def self.guard
b3a0: 5f 64 61 65 6d 6f 6e 28 61 72 67 73 20 3a 20 41 _daemon(args : A
b3b0: 72 72 61 79 28 53 74 72 69 6e 67 29 2c 20 72 65 rray(String), re
b3c0: 70 6f 73 69 74 6f 72 69 65 73 20 3a 20 53 74 72 positories : Str
b3d0: 69 6e 67 29 20 3a 20 4e 69 6c 0a 20 20 20 20 72 ing) : Nil. r
b3e0: 65 70 6f 73 69 74 6f 72 79 20 3d 20 72 65 61 6c epository = real
b3f0: 5f 62 6f 75 6e 64 28 72 65 70 6f 73 69 74 6f 72 _bound(repositor
b400: 69 65 73 29 2e 72 63 68 6f 70 28 27 2f 27 29 0a ies).rchop('/').
b410: 20 20 20 20 61 72 67 73 2e 65 61 63 68 5f 77 69 args.each_wi
b420: 74 68 5f 69 6e 64 65 78 20 64 6f 20 7c 61 72 67 th_index do |arg
b430: 2c 20 69 6e 64 65 78 7c 0a 20 20 20 20 20 20 23 , index|. #
b440: 20 6f 6e 6c 79 20 61 20 62 69 6e 64 20 62 72 69 only a bind bri
b450: 6e 67 73 20 61 20 68 6f 73 74 20 70 61 74 68 20 ngs a host path
b460: 69 6e 3b 20 2d 2d 74 6d 70 66 73 2c 20 2d 2d 70 in; --tmpfs, --p
b470: 72 6f 63 20 61 6e 64 20 2d 2d 64 65 76 20 6d 61 roc and --dev ma
b480: 6b 65 20 66 72 65 73 68 2c 20 65 6d 70 74 79 20 ke fresh, empty
b490: 6f 6e 65 73 0a 20 20 20 20 20 20 6e 65 78 74 20 ones. next
b4a0: 75 6e 6c 65 73 73 20 7b 22 2d 2d 62 69 6e 64 22 unless {"--bind"
b4b0: 2c 20 22 2d 2d 62 69 6e 64 2d 74 72 79 22 2c 20 , "--bind-try",
b4c0: 22 2d 2d 72 6f 2d 62 69 6e 64 22 2c 20 22 2d 2d "--ro-bind", "--
b4d0: 72 6f 2d 62 69 6e 64 2d 74 72 79 22 7d 2e 69 6e ro-bind-try"}.in
b4e0: 63 6c 75 64 65 73 3f 28 61 72 67 29 0a 20 20 20 cludes?(arg).
b4f0: 20 20 20 70 61 74 68 20 3d 20 72 65 61 6c 5f 62 path = real_b
b500: 6f 75 6e 64 28 61 72 67 73 5b 69 6e 64 65 78 20 ound(args[index
b510: 2b 20 31 5d 29 2e 72 63 68 6f 70 28 27 2f 27 29 + 1]).rchop('/')
b520: 0a 20 20 20 20 20 20 69 66 20 70 61 74 68 20 3d . if path =
b530: 3d 20 72 65 70 6f 73 69 74 6f 72 79 20 7c 7c 20 = repository ||
b540: 70 61 74 68 2e 73 74 61 72 74 73 5f 77 69 74 68 path.starts_with
b550: 3f 28 72 65 70 6f 73 69 74 6f 72 79 20 2b 20 22 ?(repository + "
b560: 2f 22 29 20 7c 7c 20 72 65 70 6f 73 69 74 6f 72 /") || repositor
b570: 79 2e 73 74 61 72 74 73 5f 77 69 74 68 3f 28 70 y.starts_with?(p
b580: 61 74 68 20 2b 20 22 2f 22 29 0a 20 20 20 20 20 ath + "/").
b590: 20 20 20 72 61 69 73 65 20 41 72 67 75 6d 65 6e raise Argumen
b5a0: 74 45 72 72 6f 72 2e 6e 65 77 28 22 64 61 65 6d tError.new("daem
b5b0: 6f 6e 20 62 6f 75 6e 64 20 70 61 74 68 20 6f 76 on bound path ov
b5c0: 65 72 6c 61 70 73 20 73 65 72 76 65 64 20 72 65 erlaps served re
b5d0: 70 6f 73 69 74 6f 72 69 65 73 22 29 0a 20 20 20 positories").
b5e0: 20 20 20 65 6e 64 0a 20 20 20 20 65 6e 64 0a 20 end. end.
b5f0: 20 65 6e 64 0a 0a 20 20 64 65 66 20 73 65 6c 66 end.. def self
b600: 2e 63 6c 6f 73 65 5f 69 6e 68 65 72 69 74 65 64 .close_inherited
b610: 20 3a 20 4e 69 6c 0a 20 20 20 20 64 69 72 20 3d : Nil. dir =
b620: 20 4c 69 62 43 2e 6f 70 65 6e 64 69 72 28 22 2f LibC.opendir("/
b630: 70 72 6f 63 2f 73 65 6c 66 2f 66 64 22 29 0a 20 proc/self/fd").
b640: 20 20 20 72 61 69 73 65 20 49 4f 3a 3a 45 72 72 raise IO::Err
b650: 6f 72 2e 66 72 6f 6d 5f 65 72 72 6e 6f 28 22 6f or.from_errno("o
b660: 70 65 6e 64 69 72 22 29 20 69 66 20 64 69 72 2e pendir") if dir.
b670: 6e 75 6c 6c 3f 0a 20 20 20 20 62 65 67 69 6e 0a null?. begin.
b680: 20 20 20 20 20 20 6f 77 6e 20 3d 20 4c 69 62 43 own = LibC
b690: 2e 64 69 72 66 64 28 64 69 72 29 0a 20 20 20 20 .dirfd(dir).
b6a0: 20 20 77 68 69 6c 65 20 65 6e 74 72 79 20 3d 20 while entry =
b6b0: 4c 69 62 43 2e 72 65 61 64 64 69 72 28 64 69 72 LibC.readdir(dir
b6c0: 29 0a 20 20 20 20 20 20 20 20 66 64 20 3d 20 53 ). fd = S
b6d0: 74 72 69 6e 67 2e 6e 65 77 28 65 6e 74 72 79 2e tring.new(entry.
b6e0: 76 61 6c 75 65 2e 64 5f 6e 61 6d 65 2e 74 6f 5f value.d_name.to_
b6f0: 75 6e 73 61 66 65 29 2e 74 6f 5f 69 3f 0a 20 20 unsafe).to_i?.
b700: 20 20 20 20 20 20 4c 69 62 43 2e 63 6c 6f 73 65 LibC.close
b710: 28 66 64 29 20 69 66 20 66 64 20 26 26 20 66 64 (fd) if fd && fd
b720: 20 3e 20 32 20 26 26 20 66 64 20 21 3d 20 6f 77 > 2 && fd != ow
b730: 6e 0a 20 20 20 20 20 20 65 6e 64 0a 20 20 20 20 n. end.
b740: 65 6e 73 75 72 65 0a 20 20 20 20 20 20 4c 69 62 ensure. Lib
b750: 43 2e 63 6c 6f 73 65 64 69 72 28 64 69 72 29 0a C.closedir(dir).
b760: 20 20 20 20 65 6e 64 0a 20 20 65 6e 64 0a 0a 20 end. end..
b770: 20 64 65 66 20 73 65 6c 66 2e 63 67 69 28 70 61 def self.cgi(pa
b780: 74 68 73 20 3a 20 50 61 74 68 73 29 20 3a 20 4e ths : Paths) : N
b790: 6f 52 65 74 75 72 6e 0a 20 20 20 20 72 65 6c 65 oReturn. rele
b7a0: 61 73 65 20 3d 20 46 69 6c 65 2e 72 65 61 6c 70 ase = File.realp
b7b0: 61 74 68 28 46 69 6c 65 2e 6a 6f 69 6e 28 70 61 ath(File.join(pa
b7c0: 74 68 73 2e 72 65 6c 65 61 73 65 2c 20 22 63 75 ths.release, "cu
b7d0: 72 72 65 6e 74 22 29 29 0a 20 20 20 20 63 6c 6f rrent")). clo
b7e0: 73 65 5f 69 6e 68 65 72 69 74 65 64 0a 20 20 20 se_inherited.
b7f0: 20 75 6e 6c 65 73 73 20 45 4e 56 5b 22 50 41 54 unless ENV["PAT
b800: 48 5f 49 4e 46 4f 22 5d 3f 20 3d 3d 20 22 2f 72 H_INFO"]? == "/r
b810: 65 63 65 69 70 74 22 0a 20 20 20 20 20 20 23 20 eceipt". #
b820: 45 36 3a 20 74 68 69 73 20 70 61 73 73 74 68 72 E6: this passthr
b830: 6f 75 67 68 20 67 6f 65 73 20 77 68 65 6e 20 74 ough goes when t
b840: 68 65 20 43 47 49 20 74 61 6c 6b 73 20 74 6f 20 he CGI talks to
b850: 74 68 65 20 64 61 65 6d 6f 6e 2e 0a 20 20 20 20 the daemon..
b860: 20 20 65 78 65 63 75 74 61 62 6c 65 20 3d 20 46 executable = F
b870: 69 6c 65 2e 6a 6f 69 6e 28 72 65 6c 65 61 73 65 ile.join(release
b880: 2c 20 22 6f 63 78 32 22 29 0a 20 20 20 20 20 20 , "ocx2").
b890: 61 72 67 76 20 3d 20 5b 46 69 6c 65 2e 6a 6f 69 argv = [File.joi
b8a0: 6e 28 72 65 6c 65 61 73 65 2c 20 22 6f 63 78 32 n(release, "ocx2
b8b0: 2d 63 67 69 22 29 2e 74 6f 5f 75 6e 73 61 66 65 -cgi").to_unsafe
b8c0: 2c 20 50 6f 69 6e 74 65 72 28 55 49 6e 74 38 29 , Pointer(UInt8)
b8d0: 2e 6e 75 6c 6c 5d 0a 20 20 20 20 20 20 4c 69 62 .null]. Lib
b8e0: 43 2e 65 78 65 63 76 28 65 78 65 63 75 74 61 62 C.execv(executab
b8f0: 6c 65 2c 20 61 72 67 76 2e 74 6f 5f 75 6e 73 61 le, argv.to_unsa
b900: 66 65 29 0a 20 20 20 20 20 20 72 61 69 73 65 20 fe). raise
b910: 49 4f 3a 3a 45 72 72 6f 72 2e 66 72 6f 6d 5f 65 IO::Error.from_e
b920: 72 72 6e 6f 28 22 65 78 65 63 76 22 29 0a 20 20 rrno("execv").
b930: 20 20 65 6e 64 0a 20 20 20 20 72 65 70 6f 73 69 end. reposi
b940: 74 6f 72 79 20 3d 20 46 69 6c 65 2e 62 61 73 65 tory = File.base
b950: 6e 61 6d 65 28 45 4e 56 5b 22 46 4f 53 53 49 4c name(ENV["FOSSIL
b960: 5f 52 45 50 4f 53 49 54 4f 52 59 22 5d 3f 20 7c _REPOSITORY"]? |
b970: 7c 20 22 22 2c 20 22 2e 66 6f 73 73 69 6c 22 29 | "", ".fossil")
b980: 0a 20 20 20 20 62 65 67 69 6e 0a 20 20 20 20 20 . begin.
b990: 20 23 20 55 73 65 20 62 6c 6f 63 6b 69 6e 67 20 # Use blocking
b9a0: 73 79 73 63 61 6c 6c 73 20 61 66 74 65 72 20 63 syscalls after c
b9b0: 6c 6f 73 69 6e 67 20 64 65 73 63 72 69 70 74 6f losing descripto
b9c0: 72 73 2c 20 69 6e 63 6c 75 64 69 6e 67 20 72 75 rs, including ru
b9d0: 6e 74 69 6d 65 20 65 76 65 6e 74 20 66 64 73 2e ntime event fds.
b9e0: 0a 20 20 20 20 20 20 61 64 64 72 65 73 73 20 3d . address =
b9f0: 20 53 6f 63 6b 65 74 3a 3a 55 4e 49 58 41 64 64 Socket::UNIXAdd
ba00: 72 65 73 73 2e 6e 65 77 28 70 61 74 68 73 2e 73 ress.new(paths.s
ba10: 6f 63 6b 65 74 29 0a 20 20 20 20 20 20 66 64 20 ocket). fd
ba20: 3d 20 4c 69 62 43 2e 73 6f 63 6b 65 74 28 4c 69 = LibC.socket(Li
ba30: 62 43 3a 3a 41 46 5f 55 4e 49 58 2c 20 4c 69 62 bC::AF_UNIX, Lib
ba40: 43 3a 3a 53 4f 43 4b 5f 53 54 52 45 41 4d 2c 20 C::SOCK_STREAM,
ba50: 30 29 0a 20 20 20 20 20 20 72 61 69 73 65 20 49 0). raise I
ba60: 4f 3a 3a 45 72 72 6f 72 2e 66 72 6f 6d 5f 65 72 O::Error.from_er
ba70: 72 6e 6f 28 22 73 6f 63 6b 65 74 22 29 20 69 66 rno("socket") if
ba80: 20 66 64 20 3d 3d 20 2d 31 0a 20 20 20 20 20 20 fd == -1.
ba90: 72 61 69 73 65 20 49 4f 3a 3a 45 72 72 6f 72 2e raise IO::Error.
baa0: 66 72 6f 6d 5f 65 72 72 6e 6f 28 22 63 6f 6e 6e from_errno("conn
bab0: 65 63 74 22 29 20 69 66 20 4c 69 62 43 2e 63 6f ect") if LibC.co
bac0: 6e 6e 65 63 74 28 66 64 2c 20 61 64 64 72 65 73 nnect(fd, addres
bad0: 73 2c 20 61 64 64 72 65 73 73 2e 73 69 7a 65 29 s, address.size)
bae0: 20 3d 3d 20 2d 31 0a 20 20 20 20 20 20 69 64 65 == -1. ide
baf0: 6e 74 69 74 79 20 3d 20 4a 53 4f 4e 2e 62 75 69 ntity = JSON.bui
bb00: 6c 64 20 64 6f 20 7c 6a 73 6f 6e 7c 0a 20 20 20 ld do |json|.
bb10: 20 20 20 20 20 6a 73 6f 6e 2e 6f 62 6a 65 63 74 json.object
bb20: 20 64 6f 0a 20 20 20 20 20 20 20 20 20 20 69 66 do. if
bb30: 20 75 73 65 72 20 3d 20 45 4e 56 5b 22 46 4f 53 user = ENV["FOS
bb40: 53 49 4c 5f 55 53 45 52 22 5d 3f 0a 20 20 20 20 SIL_USER"]?.
bb50: 20 20 20 20 20 20 20 20 6a 73 6f 6e 2e 66 69 65 json.fie
bb60: 6c 64 20 22 75 73 65 72 22 2c 20 75 73 65 72 0a ld "user", user.
bb70: 20 20 20 20 20 20 20 20 20 20 65 6e 64 0a 20 20 end.
bb80: 20 20 20 20 20 20 20 20 6a 73 6f 6e 2e 66 69 65 json.fie
bb90: 6c 64 20 22 63 61 70 61 62 69 6c 69 74 69 65 73 ld "capabilities
bba0: 22 2c 20 45 4e 56 5b 22 46 4f 53 53 49 4c 5f 43 ", ENV["FOSSIL_C
bbb0: 41 50 41 42 49 4c 49 54 49 45 53 22 5d 3f 20 7c APABILITIES"]? |
bbc0: 7c 20 22 22 0a 20 20 20 20 20 20 20 20 20 20 6a | "". j
bbd0: 73 6f 6e 2e 66 69 65 6c 64 20 22 72 65 70 6f 73 son.field "repos
bbe0: 69 74 6f 72 79 22 2c 20 72 65 70 6f 73 69 74 6f itory", reposito
bbf0: 72 79 0a 20 20 20 20 20 20 20 20 65 6e 64 0a 20 ry. end.
bc00: 20 20 20 20 20 65 6e 64 0a 20 20 20 20 20 20 62 end. b
bc10: 79 74 65 73 20 3d 20 28 69 64 65 6e 74 69 74 79 ytes = (identity
bc20: 20 2b 20 22 5c 6e 22 29 2e 74 6f 5f 73 6c 69 63 + "\n").to_slic
bc30: 65 0a 20 20 20 20 20 20 75 6e 74 69 6c 20 62 79 e. until by
bc40: 74 65 73 2e 65 6d 70 74 79 3f 0a 20 20 20 20 20 tes.empty?.
bc50: 20 20 20 77 72 69 74 74 65 6e 20 3d 20 4c 69 62 written = Lib
bc60: 43 2e 77 72 69 74 65 28 66 64 2c 20 62 79 74 65 C.write(fd, byte
bc70: 73 2c 20 62 79 74 65 73 2e 73 69 7a 65 29 0a 20 s, bytes.size).
bc80: 20 20 20 20 20 20 20 6e 65 78 74 20 69 66 20 77 next if w
bc90: 72 69 74 74 65 6e 20 3d 3d 20 2d 31 20 26 26 20 ritten == -1 &&
bca0: 45 72 72 6e 6f 2e 76 61 6c 75 65 20 3d 3d 20 45 Errno.value == E
bcb0: 72 72 6e 6f 3a 3a 45 49 4e 54 52 0a 20 20 20 20 rrno::EINTR.
bcc0: 20 20 20 20 72 61 69 73 65 20 49 4f 3a 3a 45 72 raise IO::Er
bcd0: 72 6f 72 2e 66 72 6f 6d 5f 65 72 72 6e 6f 28 22 ror.from_errno("
bce0: 77 72 69 74 65 22 29 20 69 66 20 77 72 69 74 74 write") if writt
bcf0: 65 6e 20 3c 3d 20 30 0a 20 20 20 20 20 20 20 20 en <= 0.
bd00: 62 79 74 65 73 20 3d 20 62 79 74 65 73 5b 77 72 bytes = bytes[wr
bd10: 69 74 74 65 6e 2e 74 6f 5f 69 2e 2e 5d 0a 20 20 itten.to_i..].
bd20: 20 20 20 20 65 6e 64 0a 20 20 20 20 72 65 73 63 end. resc
bd30: 75 65 20 53 6f 63 6b 65 74 3a 3a 45 72 72 6f 72 ue Socket::Error
bd40: 20 7c 20 49 4f 3a 3a 45 72 72 6f 72 0a 20 20 20 | IO::Error.
bd50: 20 20 20 23 20 54 68 65 20 72 75 6e 74 69 6d 65 # The runtime
bd60: 27 73 20 6f 77 6e 20 64 65 73 63 72 69 70 74 6f 's own descripto
bd70: 72 73 20 61 72 65 20 63 6c 6f 73 65 64 2c 20 73 rs are closed, s
bd80: 6f 20 77 72 69 74 65 20 77 69 74 68 20 74 68 65 o write with the
bd90: 20 73 79 73 74 65 6d 20 63 61 6c 6c 20 69 74 73 system call its
bda0: 65 6c 66 2e 0a 20 20 20 20 20 20 61 6e 73 77 65 elf.. answe
bdb0: 72 20 3d 20 22 53 74 61 74 75 73 3a 20 35 30 33 r = "Status: 503
bdc0: 5c 72 5c 6e 43 6f 6e 74 65 6e 74 2d 54 79 70 65 \r\nContent-Type
bdd0: 3a 20 61 70 70 6c 69 63 61 74 69 6f 6e 2f 6a 73 : application/js
bde0: 6f 6e 5c 72 5c 6e 5c 72 5c 6e 7b 5c 22 75 6e 61 on\r\n\r\n{\"una
bdf0: 76 61 69 6c 61 62 6c 65 5c 22 3a 5c 22 72 65 63 vailable\":\"rec
be00: 65 69 70 74 20 73 65 72 76 69 63 65 20 6e 6f 74 eipt service not
be10: 20 61 6e 73 77 65 72 69 6e 67 5c 22 7d 5c 6e 22 answering\"}\n"
be20: 2e 74 6f 5f 73 6c 69 63 65 0a 20 20 20 20 20 20 .to_slice.
be30: 4c 69 62 43 2e 77 72 69 74 65 28 31 2c 20 61 6e LibC.write(1, an
be40: 73 77 65 72 2c 20 61 6e 73 77 65 72 2e 73 69 7a swer, answer.siz
be50: 65 29 0a 20 20 20 20 20 20 65 78 69 74 20 30 0a e). exit 0.
be60: 20 20 20 20 65 6e 64 0a 20 20 20 20 72 61 69 73 end. rais
be70: 65 20 49 4f 3a 3a 45 72 72 6f 72 2e 66 72 6f 6d e IO::Error.from
be80: 5f 65 72 72 6e 6f 28 22 64 75 70 32 22 29 20 69 _errno("dup2") i
be90: 66 20 4c 69 62 43 2e 64 75 70 32 28 66 64 2c 20 f LibC.dup2(fd,
bea0: 33 29 20 3d 3d 20 2d 31 0a 20 20 20 20 4c 69 62 3) == -1. Lib
beb0: 43 2e 63 6c 6f 73 65 28 66 64 29 20 75 6e 6c 65 C.close(fd) unle
bec0: 73 73 20 66 64 20 3d 3d 20 33 0a 20 20 20 20 72 ss fd == 3. r
bed0: 61 69 73 65 20 49 4f 3a 3a 45 72 72 6f 72 2e 66 aise IO::Error.f
bee0: 72 6f 6d 5f 65 72 72 6e 6f 28 22 66 63 6e 74 6c rom_errno("fcntl
bef0: 22 29 20 69 66 20 4c 69 62 43 2e 66 63 6e 74 6c ") if LibC.fcntl
bf00: 28 33 2c 20 4c 69 62 43 3a 3a 46 5f 53 45 54 46 (3, LibC::F_SETF
bf10: 44 2c 20 30 29 20 3d 3d 20 2d 31 0a 20 20 20 20 D, 0) == -1.
bf20: 65 6e 76 69 72 6f 6e 6d 65 6e 74 20 3d 20 7b 7d environment = {}
bf30: 20 6f 66 20 53 74 72 69 6e 67 20 3d 3e 20 53 74 of String => St
bf40: 72 69 6e 67 0a 20 20 20 20 43 47 49 5f 46 49 45 ring. CGI_FIE
bf50: 4c 44 53 2e 65 61 63 68 20 64 6f 20 7c 6b 65 79 LDS.each do |key
bf60: 7c 0a 20 20 20 20 20 20 69 66 20 76 61 6c 75 65 |. if value
bf70: 20 3d 20 45 4e 56 5b 6b 65 79 5d 3f 0a 20 20 20 = ENV[key]?.
bf80: 20 20 20 20 20 65 6e 76 69 72 6f 6e 6d 65 6e 74 environment
bf90: 5b 6b 65 79 5d 20 3d 20 76 61 6c 75 65 0a 20 20 [key] = value.
bfa0: 20 20 20 20 65 6e 64 0a 20 20 20 20 65 6e 64 0a end. end.
bfb0: 20 20 20 20 65 78 65 63 5f 72 61 77 28 22 2f 75 exec_raw("/u
bfc0: 73 72 2f 62 69 6e 2f 62 77 72 61 70 22 2c 20 63 sr/bin/bwrap", c
bfd0: 67 69 5f 61 72 67 73 28 72 65 6c 65 61 73 65 2c gi_args(release,
bfe0: 20 72 65 70 6f 73 69 74 6f 72 79 2c 20 65 6e 76 repository, env
bff0: 69 72 6f 6e 6d 65 6e 74 29 29 0a 20 20 65 6e 64 ironment)). end
c000: 0a 0a 20 20 23 20 65 78 65 63 76 20 77 69 74 68 .. # execv with
c010: 6f 75 74 20 74 68 65 20 72 75 6e 74 69 6d 65 2c out the runtime,
c020: 20 77 68 6f 73 65 20 64 65 73 63 72 69 70 74 6f whose descripto
c030: 72 73 20 63 6c 6f 73 65 5f 69 6e 68 65 72 69 74 rs close_inherit
c040: 65 64 20 68 61 73 20 63 6c 6f 73 65 64 2e 0a 20 ed has closed..
c050: 20 64 65 66 20 73 65 6c 66 2e 65 78 65 63 5f 72 def self.exec_r
c060: 61 77 28 70 72 6f 67 72 61 6d 20 3a 20 53 74 72 aw(program : Str
c070: 69 6e 67 2c 20 61 72 67 73 20 3a 20 41 72 72 61 ing, args : Arra
c080: 79 28 53 74 72 69 6e 67 29 29 20 3a 20 4e 6f 52 y(String)) : NoR
c090: 65 74 75 72 6e 0a 20 20 20 20 61 72 67 76 20 3d eturn. argv =
c0a0: 20 28 5b 70 72 6f 67 72 61 6d 5d 20 2b 20 61 72 ([program] + ar
c0b0: 67 73 29 2e 6d 61 70 28 26 2e 74 6f 5f 75 6e 73 gs).map(&.to_uns
c0c0: 61 66 65 29 20 2b 20 5b 50 6f 69 6e 74 65 72 28 afe) + [Pointer(
c0d0: 55 49 6e 74 38 29 2e 6e 75 6c 6c 5d 0a 20 20 20 UInt8).null].
c0e0: 20 4c 69 62 43 2e 65 78 65 63 76 28 70 72 6f 67 LibC.execv(prog
c0f0: 72 61 6d 2c 20 61 72 67 76 2e 74 6f 5f 75 6e 73 ram, argv.to_uns
c100: 61 66 65 29 0a 20 20 20 20 72 61 69 73 65 20 49 afe). raise I
c110: 4f 3a 3a 45 72 72 6f 72 2e 66 72 6f 6d 5f 65 72 O::Error.from_er
c120: 72 6e 6f 28 22 65 78 65 63 76 22 29 0a 20 20 65 rno("execv"). e
c130: 6e 64 0a 0a 20 20 64 65 66 20 73 65 6c 66 2e 72 nd.. def self.r
c140: 75 6e 20 3a 20 4e 6f 52 65 74 75 72 6e 0a 20 20 un : NoReturn.
c150: 20 20 61 72 67 73 20 3d 20 41 52 47 56 2e 64 75 args = ARGV.du
c160: 70 0a 20 20 20 20 73 63 72 61 74 63 68 20 3d 20 p. scratch =
c170: 6e 69 6c 0a 20 20 20 20 69 66 20 61 72 67 73 2e nil. if args.
c180: 66 69 72 73 74 3f 20 3d 3d 20 22 2d 2d 73 63 72 first? == "--scr
c190: 61 74 63 68 22 0a 20 20 20 20 20 20 61 72 67 73 atch". args
c1a0: 2e 73 68 69 66 74 0a 20 20 20 20 20 20 73 63 72 .shift. scr
c1b0: 61 74 63 68 20 3d 20 61 72 67 73 2e 73 68 69 66 atch = args.shif
c1c0: 74 3f 20 7c 7c 20 72 61 69 73 65 20 41 72 67 75 t? || raise Argu
c1d0: 6d 65 6e 74 45 72 72 6f 72 2e 6e 65 77 28 22 6d mentError.new("m
c1e0: 69 73 73 69 6e 67 20 73 63 72 61 74 63 68 20 64 issing scratch d
c1f0: 69 72 65 63 74 6f 72 79 22 29 0a 20 20 20 20 65 irectory"). e
c200: 6e 64 0a 20 20 20 20 63 67 69 5f 6d 6f 64 65 20 nd. cgi_mode
c210: 3d 20 46 69 6c 65 2e 62 61 73 65 6e 61 6d 65 28 = File.basename(
c220: 50 52 4f 47 52 41 4d 5f 4e 41 4d 45 29 20 3d 3d PROGRAM_NAME) ==
c230: 20 22 6f 63 78 32 2d 63 67 69 22 0a 20 20 20 20 "ocx2-cgi".
c240: 75 6e 6c 65 73 73 20 28 63 67 69 5f 6d 6f 64 65 unless (cgi_mode
c250: 20 26 26 20 61 72 67 73 2e 65 6d 70 74 79 3f 29 && args.empty?)
c260: 20 7c 7c 20 28 21 63 67 69 5f 6d 6f 64 65 20 26 || (!cgi_mode &
c270: 26 20 61 72 67 73 2e 73 69 7a 65 20 3d 3d 20 31 & args.size == 1
c280: 20 26 26 20 7b 22 72 65 63 65 69 70 74 73 22 2c && {"receipts",
c290: 20 22 64 61 65 6d 6f 6e 22 7d 2e 69 6e 63 6c 75 "daemon"}.inclu
c2a0: 64 65 73 3f 28 61 72 67 73 5b 30 5d 29 29 0a 20 des?(args[0])).
c2b0: 20 20 20 20 20 72 61 69 73 65 20 41 72 67 75 6d raise Argum
c2c0: 65 6e 74 45 72 72 6f 72 2e 6e 65 77 28 22 75 6e entError.new("un
c2d0: 72 65 63 6f 67 6e 69 73 65 64 20 6d 6f 64 65 22 recognised mode"
c2e0: 29 0a 20 20 20 20 65 6e 64 0a 20 20 20 20 70 61 ). end. pa
c2f0: 74 68 73 20 3d 20 70 61 74 68 73 28 73 63 72 61 ths = paths(scra
c300: 74 63 68 2c 20 53 79 73 74 65 6d 2e 68 6f 73 74 tch, System.host
c310: 6e 61 6d 65 29 0a 20 20 20 20 63 67 69 28 70 61 name). cgi(pa
c320: 74 68 73 29 20 69 66 20 63 67 69 5f 6d 6f 64 65 ths) if cgi_mode
c330: 0a 20 20 20 20 65 78 65 63 75 74 61 62 6c 65 20 . executable
c340: 3d 20 50 72 6f 63 65 73 73 2e 65 78 65 63 75 74 = Process.execut
c350: 61 62 6c 65 5f 70 61 74 68 20 7c 7c 20 72 61 69 able_path || rai
c360: 73 65 20 41 72 67 75 6d 65 6e 74 45 72 72 6f 72 se ArgumentError
c370: 2e 6e 65 77 28 22 63 61 6e 6e 6f 74 20 6c 6f 63 .new("cannot loc
c380: 61 74 65 20 65 78 65 63 75 74 61 62 6c 65 22 29 ate executable")
c390: 0a 20 20 20 20 69 66 20 61 72 67 73 5b 30 5d 20 . if args[0]
c3a0: 3d 3d 20 22 72 65 63 65 69 70 74 73 22 0a 20 20 == "receipts".
c3b0: 20 20 20 20 63 6f 6d 6d 61 6e 64 20 3d 20 72 65 command = re
c3c0: 63 65 69 70 74 73 5f 61 72 67 73 28 70 61 74 68 ceipts_args(path
c3d0: 73 2c 20 46 69 6c 65 2e 64 69 72 6e 61 6d 65 28 s, File.dirname(
c3e0: 65 78 65 63 75 74 61 62 6c 65 29 29 0a 20 20 20 executable)).
c3f0: 20 65 6c 73 65 0a 20 20 20 20 20 20 63 6f 6d 6d else. comm
c400: 61 6e 64 20 3d 20 64 61 65 6d 6f 6e 5f 61 72 67 and = daemon_arg
c410: 73 28 70 61 74 68 73 2c 20 70 61 74 68 73 2e 68 s(paths, paths.h
c420: 6f 6d 65 73 2e 73 65 6c 65 63 74 20 7b 20 7c 70 omes.select { |p
c430: 61 74 68 2c 20 5f 7c 20 46 69 6c 65 2e 65 78 69 ath, _| File.exi
c440: 73 74 73 3f 28 70 61 74 68 29 20 7d 29 0a 20 20 sts?(path) }).
c450: 20 20 20 20 67 75 61 72 64 5f 64 61 65 6d 6f 6e guard_daemon
c460: 28 63 6f 6d 6d 61 6e 64 2c 20 70 61 74 68 73 2e (command, paths.
c470: 72 65 70 6f 73 69 74 6f 72 69 65 73 29 0a 20 20 repositories).
c480: 20 20 65 6e 64 0a 20 20 20 20 50 72 6f 63 65 73 end. Proces
c490: 73 2e 65 78 65 63 28 22 2f 75 73 72 2f 62 69 6e s.exec("/usr/bin
c4a0: 2f 62 77 72 61 70 22 2c 20 63 6f 6d 6d 61 6e 64 /bwrap", command
c4b0: 29 0a 20 20 72 65 73 63 75 65 20 65 78 20 3a 20 ). rescue ex :
c4c0: 41 72 67 75 6d 65 6e 74 45 72 72 6f 72 20 7c 20 ArgumentError |
c4d0: 49 4f 3a 3a 45 72 72 6f 72 0a 20 20 20 20 53 54 IO::Error. ST
c4e0: 44 45 52 52 2e 70 75 74 73 20 22 23 7b 65 78 2e DERR.puts "#{ex.
c4f0: 6d 65 73 73 61 67 65 7d 5c 6e 55 73 61 67 65 3a message}\nUsage:
c500: 20 73 74 61 72 74 2d 6f 63 78 20 5b 2d 2d 73 63 start-ocx [--sc
c510: 72 61 74 63 68 20 44 49 52 5d 20 72 65 63 65 69 ratch DIR] recei
c520: 70 74 73 7c 64 61 65 6d 6f 6e 3b 20 6f 63 78 32 pts|daemon; ocx2
c530: 2d 63 67 69 20 5b 2d 2d 73 63 72 61 74 63 68 20 -cgi [--scratch
c540: 44 49 52 5d 22 0a 20 20 20 20 65 78 69 74 20 32 DIR]". exit 2
c550: 0a 20 20 65 6e 64 0a 65 6e 64 0a 0a 53 74 61 72 . end.end..Star
c560: 74 4f 43 58 2e 72 75 6e 0a 00 00 00 00 00 00 00 tOCX.run........
c570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c590: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c5a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c5b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c5c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c5d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c5e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c5f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c600: 73 74 61 67 65 41 2d 72 65 63 6f 72 64 2f 72 65 stageA-record/re
c610: 63 65 69 70 74 73 2e 63 72 00 00 00 00 00 00 00 ceipts.cr.......
c620: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c630: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c640: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c650: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c660: 00 00 00 00 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000
c670: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
c680: 30 30 33 30 32 34 35 00 31 35 32 37 30 34 37 36 0030245.15270476
c690: 32 30 35 00 30 31 34 34 31 34 00 20 30 00 00 00 205.014414. 0...
c6a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c6b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c6c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c6d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c6e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c6f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c700: 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
c710: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c720: 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
c730: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c740: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c750: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c760: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c770: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c7a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c7b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c7c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c7d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c7e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c7f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c800: 23 20 41 67 65 6e 74 73 3a 20 64 6f 20 6e 6f 74 # Agents: do not
c810: 20 63 68 61 6e 67 65 20 74 68 69 73 20 66 69 6c change this fil
c820: 65 20 6f 6e 20 61 6e 79 20 62 72 61 6e 63 68 20 e on any branch
c830: 77 69 74 68 6f 75 74 20 74 68 65 20 6d 61 69 6e without the main
c840: 74 61 69 6e 65 72 27 73 20 65 78 70 6c 69 63 69 tainer's explici
c850: 74 20 61 70 70 72 6f 76 61 6c 20 6f 6e 20 74 68 t approval on th
c860: 65 20 72 65 63 6f 72 64 2e 0a 23 20 53 65 6c 66 e record..# Self
c870: 2d 63 6f 6e 74 61 69 6e 65 64 2c 20 73 74 61 6e -contained, stan
c880: 64 61 72 64 2d 6c 69 62 72 61 72 79 2d 6f 6e 6c dard-library-onl
c890: 79 20 72 65 63 65 69 70 74 20 73 65 72 76 69 63 y receipt servic
c8a0: 65 2e 20 55 73 61 67 65 3a 20 72 65 63 65 69 70 e. Usage: receip
c8b0: 74 73 20 53 4f 43 4b 45 54 20 52 45 50 4f 53 49 ts SOCKET REPOSI
c8c0: 54 4f 52 49 45 53 2e 0a 23 20 52 65 61 64 73 20 TORIES..# Reads
c8d0: 6f 6e 6c 79 20 69 74 73 20 74 77 6f 20 4a 53 4f only its two JSO
c8e0: 4e 20 6c 69 6e 65 73 20 61 6e 64 20 52 45 50 4f N lines and REPO
c8f0: 53 49 54 4f 52 49 45 53 2f 4e 41 4d 45 2e 66 6f SITORIES/NAME.fo
c900: 73 73 69 6c 2c 20 72 65 61 64 2d 6f 6e 6c 79 20 ssil, read-only
c910: 74 68 72 6f 75 67 68 20 53 51 4c 69 74 65 2e 0a through SQLite..
c920: 72 65 71 75 69 72 65 20 22 6a 73 6f 6e 22 0a 72 require "json".r
c930: 65 71 75 69 72 65 20 22 73 6f 63 6b 65 74 22 0a equire "socket".
c940: 72 65 71 75 69 72 65 20 22 75 72 69 22 0a 72 65 require "uri".re
c950: 71 75 69 72 65 20 22 73 65 74 22 0a 0a 6c 69 62 quire "set"..lib
c960: 20 52 65 63 65 69 70 74 50 65 65 72 0a 20 20 73 ReceiptPeer. s
c970: 74 72 75 63 74 20 43 72 65 64 65 6e 74 69 61 6c truct Credential
c980: 73 0a 20 20 20 20 70 69 64 20 3a 20 49 6e 74 33 s. pid : Int3
c990: 32 0a 20 20 20 20 75 69 64 20 3a 20 55 49 6e 74 2. uid : UInt
c9a0: 33 32 0a 20 20 20 20 67 69 64 20 3a 20 55 49 6e 32. gid : UIn
c9b0: 74 33 32 0a 20 20 65 6e 64 0a 0a 20 20 66 75 6e t32. end.. fun
c9c0: 20 67 65 74 73 6f 63 6b 6f 70 74 20 3d 20 67 65 getsockopt = ge
c9d0: 74 73 6f 63 6b 6f 70 74 28 66 64 20 3a 20 49 6e tsockopt(fd : In
c9e0: 74 33 32 2c 20 6c 65 76 65 6c 20 3a 20 49 6e 74 t32, level : Int
c9f0: 33 32 2c 20 6f 70 74 69 6f 6e 20 3a 20 49 6e 74 32, option : Int
ca00: 33 32 2c 20 76 61 6c 75 65 20 3a 20 56 6f 69 64 32, value : Void
ca10: 2a 2c 20 73 69 7a 65 20 3a 20 55 49 6e 74 33 32 *, size : UInt32
ca20: 2a 29 20 3a 20 49 6e 74 33 32 0a 65 6e 64 0a 0a *) : Int32.end..
ca30: 40 5b 4c 69 6e 6b 28 22 73 71 6c 69 74 65 33 22 @[Link("sqlite3"
ca40: 29 5d 0a 6c 69 62 20 4c 69 62 53 51 4c 69 74 65 )].lib LibSQLite
ca50: 33 0a 20 20 66 75 6e 20 6f 70 65 6e 5f 76 32 20 3. fun open_v2
ca60: 3d 20 73 71 6c 69 74 65 33 5f 6f 70 65 6e 5f 76 = sqlite3_open_v
ca70: 32 28 70 61 74 68 20 3a 20 55 49 6e 74 38 2a 2c 2(path : UInt8*,
ca80: 20 64 62 20 3a 20 56 6f 69 64 2a 2a 2c 20 66 6c db : Void**, fl
ca90: 61 67 73 20 3a 20 49 6e 74 33 32 2c 20 76 66 73 ags : Int32, vfs
caa0: 20 3a 20 55 49 6e 74 38 2a 29 20 3a 20 49 6e 74 : UInt8*) : Int
cab0: 33 32 0a 20 20 66 75 6e 20 63 6c 6f 73 65 5f 76 32. fun close_v
cac0: 32 20 3d 20 73 71 6c 69 74 65 33 5f 63 6c 6f 73 2 = sqlite3_clos
cad0: 65 5f 76 32 28 64 62 20 3a 20 56 6f 69 64 2a 29 e_v2(db : Void*)
cae0: 20 3a 20 49 6e 74 33 32 0a 20 20 66 75 6e 20 70 : Int32. fun p
caf0: 72 65 70 61 72 65 5f 76 32 20 3d 20 73 71 6c 69 repare_v2 = sqli
cb00: 74 65 33 5f 70 72 65 70 61 72 65 5f 76 32 28 64 te3_prepare_v2(d
cb10: 62 20 3a 20 56 6f 69 64 2a 2c 20 73 71 6c 20 3a b : Void*, sql :
cb20: 20 55 49 6e 74 38 2a 2c 20 73 69 7a 65 20 3a 20 UInt8*, size :
cb30: 49 6e 74 33 32 2c 20 73 74 61 74 65 6d 65 6e 74 Int32, statement
cb40: 20 3a 20 56 6f 69 64 2a 2a 2c 20 74 61 69 6c 20 : Void**, tail
cb50: 3a 20 55 49 6e 74 38 2a 2a 29 20 3a 20 49 6e 74 : UInt8**) : Int
cb60: 33 32 0a 20 20 66 75 6e 20 62 69 6e 64 5f 74 65 32. fun bind_te
cb70: 78 74 20 3d 20 73 71 6c 69 74 65 33 5f 62 69 6e xt = sqlite3_bin
cb80: 64 5f 74 65 78 74 28 73 74 61 74 65 6d 65 6e 74 d_text(statement
cb90: 20 3a 20 56 6f 69 64 2a 2c 20 69 6e 64 65 78 20 : Void*, index
cba0: 3a 20 49 6e 74 33 32 2c 20 74 65 78 74 20 3a 20 : Int32, text :
cbb0: 55 49 6e 74 38 2a 2c 20 73 69 7a 65 20 3a 20 49 UInt8*, size : I
cbc0: 6e 74 33 32 2c 20 64 65 73 74 72 75 63 74 6f 72 nt32, destructor
cbd0: 20 3a 20 56 6f 69 64 2a 29 20 3a 20 49 6e 74 33 : Void*) : Int3
cbe0: 32 0a 20 20 66 75 6e 20 73 74 65 70 20 3d 20 73 2. fun step = s
cbf0: 71 6c 69 74 65 33 5f 73 74 65 70 28 73 74 61 74 qlite3_step(stat
cc00: 65 6d 65 6e 74 20 3a 20 56 6f 69 64 2a 29 20 3a ement : Void*) :
cc10: 20 49 6e 74 33 32 0a 20 20 66 75 6e 20 63 6f 6c Int32. fun col
cc20: 75 6d 6e 5f 69 6e 74 36 34 20 3d 20 73 71 6c 69 umn_int64 = sqli
cc30: 74 65 33 5f 63 6f 6c 75 6d 6e 5f 69 6e 74 36 34 te3_column_int64
cc40: 28 73 74 61 74 65 6d 65 6e 74 20 3a 20 56 6f 69 (statement : Voi
cc50: 64 2a 2c 20 63 6f 6c 75 6d 6e 20 3a 20 49 6e 74 d*, column : Int
cc60: 33 32 29 20 3a 20 49 6e 74 36 34 0a 20 20 66 75 32) : Int64. fu
cc70: 6e 20 63 6f 6c 75 6d 6e 5f 74 65 78 74 20 3d 20 n column_text =
cc80: 73 71 6c 69 74 65 33 5f 63 6f 6c 75 6d 6e 5f 74 sqlite3_column_t
cc90: 65 78 74 28 73 74 61 74 65 6d 65 6e 74 20 3a 20 ext(statement :
cca0: 56 6f 69 64 2a 2c 20 63 6f 6c 75 6d 6e 20 3a 20 Void*, column :
ccb0: 49 6e 74 33 32 29 20 3a 20 55 49 6e 74 38 2a 0a Int32) : UInt8*.
ccc0: 20 20 66 75 6e 20 63 6f 6c 75 6d 6e 5f 74 79 70 fun column_typ
ccd0: 65 20 3d 20 73 71 6c 69 74 65 33 5f 63 6f 6c 75 e = sqlite3_colu
cce0: 6d 6e 5f 74 79 70 65 28 73 74 61 74 65 6d 65 6e mn_type(statemen
ccf0: 74 20 3a 20 56 6f 69 64 2a 2c 20 63 6f 6c 75 6d t : Void*, colum
cd00: 6e 20 3a 20 49 6e 74 33 32 29 20 3a 20 49 6e 74 n : Int32) : Int
cd10: 33 32 0a 20 20 66 75 6e 20 66 69 6e 61 6c 69 7a 32. fun finaliz
cd20: 65 20 3d 20 73 71 6c 69 74 65 33 5f 66 69 6e 61 e = sqlite3_fina
cd30: 6c 69 7a 65 28 73 74 61 74 65 6d 65 6e 74 20 3a lize(statement :
cd40: 20 56 6f 69 64 2a 29 20 3a 20 49 6e 74 33 32 0a Void*) : Int32.
cd50: 20 20 66 75 6e 20 65 78 65 63 20 3d 20 73 71 6c fun exec = sql
cd60: 69 74 65 33 5f 65 78 65 63 28 64 62 20 3a 20 56 ite3_exec(db : V
cd70: 6f 69 64 2a 2c 20 73 71 6c 20 3a 20 55 49 6e 74 oid*, sql : UInt
cd80: 38 2a 2c 20 63 61 6c 6c 62 61 63 6b 20 3a 20 56 8*, callback : V
cd90: 6f 69 64 2a 2c 20 63 6f 6e 74 65 78 74 20 3a 20 oid*, context :
cda0: 56 6f 69 64 2a 2c 20 65 72 72 6f 72 20 3a 20 55 Void*, error : U
cdb0: 49 6e 74 38 2a 2a 29 20 3a 20 49 6e 74 33 32 0a Int8**) : Int32.
cdc0: 20 20 66 75 6e 20 62 75 73 79 5f 74 69 6d 65 6f fun busy_timeo
cdd0: 75 74 20 3d 20 73 71 6c 69 74 65 33 5f 62 75 73 ut = sqlite3_bus
cde0: 79 5f 74 69 6d 65 6f 75 74 28 64 62 20 3a 20 56 y_timeout(db : V
cdf0: 6f 69 64 2a 2c 20 6d 69 6c 6c 69 73 65 63 6f 6e oid*, millisecon
ce00: 64 73 20 3a 20 49 6e 74 33 32 29 20 3a 20 49 6e ds : Int32) : In
ce10: 74 33 32 0a 20 20 66 75 6e 20 65 78 74 65 6e 64 t32. fun extend
ce20: 65 64 5f 65 72 72 63 6f 64 65 20 3d 20 73 71 6c ed_errcode = sql
ce30: 69 74 65 33 5f 65 78 74 65 6e 64 65 64 5f 65 72 ite3_extended_er
ce40: 72 63 6f 64 65 28 64 62 20 3a 20 56 6f 69 64 2a rcode(db : Void*
ce50: 29 20 3a 20 49 6e 74 33 32 0a 20 20 66 75 6e 20 ) : Int32. fun
ce60: 65 72 72 6d 73 67 20 3d 20 73 71 6c 69 74 65 33 errmsg = sqlite3
ce70: 5f 65 72 72 6d 73 67 28 64 62 20 3a 20 56 6f 69 _errmsg(db : Voi
ce80: 64 2a 29 20 3a 20 55 49 6e 74 38 2a 0a 65 6e 64 d*) : UInt8*.end
ce90: 0a 0a 6d 6f 64 75 6c 65 20 52 65 63 65 69 70 74 ..module Receipt
cea0: 73 0a 20 20 63 6c 61 73 73 20 52 65 66 75 73 65 s. class Refuse
ceb0: 64 20 3c 20 45 78 63 65 70 74 69 6f 6e 3b 20 65 d < Exception; e
cec0: 6e 64 0a 0a 20 20 63 6c 61 73 73 20 55 6e 61 76 nd.. class Unav
ced0: 61 69 6c 61 62 6c 65 20 3c 20 45 78 63 65 70 74 ailable < Except
cee0: 69 6f 6e 3b 20 65 6e 64 0a 0a 20 20 72 65 63 6f ion; end.. reco
cef0: 72 64 20 49 64 65 6e 74 69 74 79 2c 20 72 65 70 rd Identity, rep
cf00: 6f 73 69 74 6f 72 79 20 3a 20 53 74 72 69 6e 67 ository : String
cf10: 2c 20 63 61 70 61 62 69 6c 69 74 69 65 73 20 3a , capabilities :
cf20: 20 53 74 72 69 6e 67 0a 20 20 72 65 63 6f 72 64 String. record
cf30: 20 52 65 71 75 65 73 74 2c 20 61 72 74 69 66 61 Request, artifa
cf40: 63 74 73 20 3a 20 41 72 72 61 79 28 53 74 72 69 cts : Array(Stri
cf50: 6e 67 29 2c 20 63 61 70 61 62 69 6c 69 74 69 65 ng), capabilitie
cf60: 73 5f 6f 66 20 3a 20 53 74 72 69 6e 67 3f 0a 0a s_of : String?..
cf70: 20 20 72 65 63 6f 72 64 20 41 72 74 69 66 61 63 record Artifac
cf80: 74 2c 20 61 72 74 69 66 61 63 74 20 3a 20 53 74 t, artifact : St
cf90: 72 69 6e 67 2c 20 72 65 63 65 69 76 65 64 20 3a ring, received :
cfa0: 20 42 6f 6f 6c 20 3d 20 66 61 6c 73 65 2c 20 73 Bool = false, s
cfb0: 65 6e 64 65 72 20 3a 20 53 74 72 69 6e 67 3f 20 ender : String?
cfc0: 3d 20 6e 69 6c 2c 0a 20 20 20 20 63 61 70 61 62 = nil,. capab
cfd0: 69 6c 69 74 69 65 73 20 3a 20 53 74 72 69 6e 67 ilities : String
cfe0: 3f 20 3d 20 6e 69 6c 2c 20 72 65 63 65 69 70 74 ? = nil, receipt
cff0: 20 3a 20 49 6e 74 36 34 3f 20 3d 20 6e 69 6c 2c : Int64? = nil,
d000: 20 72 69 64 20 3a 20 49 6e 74 36 34 3f 20 3d 20 rid : Int64? =
d010: 6e 69 6c 20 64 6f 0a 20 20 20 20 69 6e 63 6c 75 nil do. inclu
d020: 64 65 20 4a 53 4f 4e 3a 3a 53 65 72 69 61 6c 69 de JSON::Seriali
d030: 7a 61 62 6c 65 0a 20 20 65 6e 64 0a 0a 20 20 73 zable. end.. s
d040: 74 72 75 63 74 20 55 73 65 72 0a 20 20 20 20 69 truct User. i
d050: 6e 63 6c 75 64 65 20 4a 53 4f 4e 3a 3a 53 65 72 nclude JSON::Ser
d060: 69 61 6c 69 7a 61 62 6c 65 0a 20 20 20 20 67 65 ializable. ge
d070: 74 74 65 72 20 75 73 65 72 20 3a 20 53 74 72 69 tter user : Stri
d080: 6e 67 0a 20 20 20 20 40 5b 4a 53 4f 4e 3a 3a 46 ng. @[JSON::F
d090: 69 65 6c 64 28 65 6d 69 74 5f 6e 75 6c 6c 3a 20 ield(emit_null:
d0a0: 74 72 75 65 29 5d 0a 20 20 20 20 67 65 74 74 65 true)]. gette
d0b0: 72 20 63 61 70 61 62 69 6c 69 74 69 65 73 20 3a r capabilities :
d0c0: 20 53 74 72 69 6e 67 3f 0a 20 20 20 20 67 65 74 String?. get
d0d0: 74 65 72 20 77 69 6b 69 5f 6d 6f 64 65 72 61 74 ter wiki_moderat
d0e0: 65 64 20 3a 20 42 6f 6f 6c 3f 0a 20 20 20 20 67 ed : Bool?. g
d0f0: 65 74 74 65 72 20 74 69 63 6b 65 74 5f 6d 6f 64 etter ticket_mod
d100: 65 72 61 74 65 64 20 3a 20 42 6f 6f 6c 3f 0a 0a erated : Bool?..
d110: 20 20 20 20 64 65 66 20 69 6e 69 74 69 61 6c 69 def initiali
d120: 7a 65 28 40 75 73 65 72 2c 20 40 63 61 70 61 62 ze(@user, @capab
d130: 69 6c 69 74 69 65 73 20 3d 20 6e 69 6c 2c 20 40 ilities = nil, @
d140: 77 69 6b 69 5f 6d 6f 64 65 72 61 74 65 64 20 3d wiki_moderated =
d150: 20 6e 69 6c 2c 20 40 74 69 63 6b 65 74 5f 6d 6f nil, @ticket_mo
d160: 64 65 72 61 74 65 64 20 3d 20 6e 69 6c 29 3b 20 derated = nil);
d170: 65 6e 64 0a 20 20 65 6e 64 0a 0a 20 20 72 65 63 end. end.. rec
d180: 6f 72 64 20 41 6e 73 77 65 72 2c 20 61 72 74 69 ord Answer, arti
d190: 66 61 63 74 73 20 3a 20 41 72 72 61 79 28 41 72 facts : Array(Ar
d1a0: 74 69 66 61 63 74 29 2c 20 75 73 65 72 20 3a 20 tifact), user :
d1b0: 55 73 65 72 3f 20 3d 20 6e 69 6c 20 64 6f 0a 20 User? = nil do.
d1c0: 20 20 20 69 6e 63 6c 75 64 65 20 4a 53 4f 4e 3a include JSON:
d1d0: 3a 53 65 72 69 61 6c 69 7a 61 62 6c 65 0a 20 20 :Serializable.
d1e0: 65 6e 64 0a 0a 20 20 64 65 66 20 73 65 6c 66 2e end.. def self.
d1f0: 69 64 65 6e 74 69 74 79 28 6c 69 6e 65 20 3a 20 identity(line :
d200: 53 74 72 69 6e 67 2c 20 72 65 70 6f 73 69 74 6f String, reposito
d210: 72 69 65 73 20 3a 20 53 74 72 69 6e 67 29 20 3a ries : String) :
d220: 20 49 64 65 6e 74 69 74 79 0a 20 20 20 20 6f 62 Identity. ob
d230: 6a 65 63 74 20 3d 20 4a 53 4f 4e 2e 70 61 72 73 ject = JSON.pars
d240: 65 28 6c 69 6e 65 29 2e 61 73 5f 68 3f 0a 20 20 e(line).as_h?.
d250: 20 20 72 61 69 73 65 20 52 65 66 75 73 65 64 2e raise Refused.
d260: 6e 65 77 28 22 69 64 65 6e 74 69 74 79 20 6d 75 new("identity mu
d270: 73 74 20 62 65 20 61 6e 20 6f 62 6a 65 63 74 22 st be an object"
d280: 29 20 75 6e 6c 65 73 73 20 6f 62 6a 65 63 74 0a ) unless object.
d290: 20 20 20 20 6e 61 6d 65 20 3d 20 6f 62 6a 65 63 name = objec
d2a0: 74 5b 22 72 65 70 6f 73 69 74 6f 72 79 22 5d 3f t["repository"]?
d2b0: 2e 74 72 79 28 26 2e 61 73 5f 73 3f 29 0a 20 20 .try(&.as_s?).
d2c0: 20 20 63 61 70 73 20 3d 20 6f 62 6a 65 63 74 5b caps = object[
d2d0: 22 63 61 70 61 62 69 6c 69 74 69 65 73 22 5d 3f "capabilities"]?
d2e0: 2e 74 72 79 28 26 2e 61 73 5f 73 3f 29 0a 20 20 .try(&.as_s?).
d2f0: 20 20 69 66 20 75 73 65 72 20 3d 20 6f 62 6a 65 if user = obje
d300: 63 74 5b 22 75 73 65 72 22 5d 3f 0a 20 20 20 20 ct["user"]?.
d310: 20 20 72 61 69 73 65 20 52 65 66 75 73 65 64 2e raise Refused.
d320: 6e 65 77 28 22 69 6e 76 61 6c 69 64 20 75 73 65 new("invalid use
d330: 72 22 29 20 75 6e 6c 65 73 73 20 75 73 65 72 2e r") unless user.
d340: 72 61 77 2e 6e 69 6c 3f 20 7c 7c 20 75 73 65 72 raw.nil? || user
d350: 2e 61 73 5f 73 3f 0a 20 20 20 20 65 6e 64 0a 20 .as_s?. end.
d360: 20 20 20 72 61 69 73 65 20 52 65 66 75 73 65 64 raise Refused
d370: 2e 6e 65 77 28 22 69 6e 76 61 6c 69 64 20 63 61 .new("invalid ca
d380: 70 61 62 69 6c 69 74 69 65 73 22 29 20 75 6e 6c pabilities") unl
d390: 65 73 73 20 63 61 70 73 0a 20 20 20 20 72 61 69 ess caps. rai
d3a0: 73 65 20 52 65 66 75 73 65 64 2e 6e 65 77 28 22 se Refused.new("
d3b0: 69 6e 76 61 6c 69 64 20 72 65 70 6f 73 69 74 6f invalid reposito
d3c0: 72 79 22 29 20 75 6e 6c 65 73 73 20 6e 61 6d 65 ry") unless name
d3d0: 20 26 26 20 2f 5c 41 5b 41 2d 5a 61 2d 7a 30 2d && /\A[A-Za-z0-
d3e0: 39 5f 5d 5b 41 2d 5a 61 2d 7a 30 2d 39 2e 5f 2d 9_][A-Za-z0-9._-
d3f0: 5d 7b 30 2c 39 39 7d 5c 7a 2f 2e 6d 61 74 63 68 ]{0,99}\z/.match
d400: 65 73 3f 28 6e 61 6d 65 29 20 26 26 20 21 6e 61 es?(name) && !na
d410: 6d 65 2e 65 6e 64 73 5f 77 69 74 68 3f 28 22 2e me.ends_with?(".
d420: 66 6f 73 73 69 6c 22 29 0a 20 20 20 20 72 61 69 fossil"). rai
d430: 73 65 20 52 65 66 75 73 65 64 2e 6e 65 77 28 22 se Refused.new("
d440: 72 65 70 6f 73 69 74 6f 72 79 20 69 73 20 6e 6f repository is no
d450: 74 20 61 20 72 65 67 75 6c 61 72 20 66 69 6c 65 t a regular file
d460: 22 29 20 75 6e 6c 65 73 73 20 46 69 6c 65 2e 66 ") unless File.f
d470: 69 6c 65 3f 28 46 69 6c 65 2e 6a 6f 69 6e 28 72 ile?(File.join(r
d480: 65 70 6f 73 69 74 6f 72 69 65 73 2c 20 6e 61 6d epositories, nam
d490: 65 20 2b 20 22 2e 66 6f 73 73 69 6c 22 29 29 0a e + ".fossil")).
d4a0: 20 20 20 20 49 64 65 6e 74 69 74 79 2e 6e 65 77 Identity.new
d4b0: 28 6e 61 6d 65 2c 20 63 61 70 73 29 0a 20 20 65 (name, caps). e
d4c0: 6e 64 0a 0a 20 20 64 65 66 20 73 65 6c 66 2e 72 nd.. def self.r
d4d0: 65 71 75 65 73 74 28 6c 69 6e 65 20 3a 20 53 74 equest(line : St
d4e0: 72 69 6e 67 29 20 3a 20 52 65 71 75 65 73 74 0a ring) : Request.
d4f0: 20 20 20 20 6f 62 6a 65 63 74 20 3d 20 4a 53 4f object = JSO
d500: 4e 2e 70 61 72 73 65 28 6c 69 6e 65 29 2e 61 73 N.parse(line).as
d510: 5f 68 3f 0a 20 20 20 20 72 61 69 73 65 20 52 65 _h?. raise Re
d520: 66 75 73 65 64 2e 6e 65 77 28 22 72 65 71 75 65 fused.new("reque
d530: 73 74 20 6d 75 73 74 20 62 65 20 61 6e 20 6f 62 st must be an ob
d540: 6a 65 63 74 22 29 20 75 6e 6c 65 73 73 20 6f 62 ject") unless ob
d550: 6a 65 63 74 0a 20 20 20 20 6f 62 6a 65 63 74 2e ject. object.
d560: 65 61 63 68 5f 6b 65 79 20 7b 20 7c 6b 65 79 7c each_key { |key|
d570: 20 72 61 69 73 65 20 52 65 66 75 73 65 64 2e 6e raise Refused.n
d580: 65 77 28 22 75 6e 6b 6e 6f 77 6e 20 6b 65 79 3a ew("unknown key:
d590: 20 23 7b 6b 65 79 7d 22 29 20 75 6e 6c 65 73 73 #{key}") unless
d5a0: 20 7b 22 6f 63 78 5f 72 65 63 65 69 70 74 22 2c {"ocx_receipt",
d5b0: 20 22 61 72 74 69 66 61 63 74 73 22 2c 20 22 63 "artifacts", "c
d5c0: 61 70 61 62 69 6c 69 74 69 65 73 5f 6f 66 22 7d apabilities_of"}
d5d0: 2e 69 6e 63 6c 75 64 65 73 3f 28 6b 65 79 29 20 .includes?(key)
d5e0: 7d 0a 20 20 20 20 72 61 69 73 65 20 52 65 66 75 }. raise Refu
d5f0: 73 65 64 2e 6e 65 77 28 22 69 6e 76 61 6c 69 64 sed.new("invalid
d600: 20 6f 63 78 5f 72 65 63 65 69 70 74 22 29 20 75 ocx_receipt") u
d610: 6e 6c 65 73 73 20 6f 62 6a 65 63 74 5b 22 6f 63 nless object["oc
d620: 78 5f 72 65 63 65 69 70 74 22 5d 3f 2e 74 72 79 x_receipt"]?.try
d630: 28 26 2e 61 73 5f 69 36 34 3f 29 20 3d 3d 20 31 (&.as_i64?) == 1
d640: 0a 20 20 20 20 68 61 73 68 65 73 20 3d 20 5b 5d . hashes = []
d650: 20 6f 66 20 53 74 72 69 6e 67 0a 20 20 20 20 69 of String. i
d660: 66 20 76 61 6c 75 65 20 3d 20 6f 62 6a 65 63 74 f value = object
d670: 5b 22 61 72 74 69 66 61 63 74 73 22 5d 3f 0a 20 ["artifacts"]?.
d680: 20 20 20 20 20 6c 69 73 74 20 3d 20 76 61 6c 75 list = valu
d690: 65 2e 61 73 5f 61 3f 0a 20 20 20 20 20 20 72 61 e.as_a?. ra
d6a0: 69 73 65 20 52 65 66 75 73 65 64 2e 6e 65 77 28 ise Refused.new(
d6b0: 22 69 6e 76 61 6c 69 64 20 61 72 74 69 66 61 63 "invalid artifac
d6c0: 74 73 22 29 20 75 6e 6c 65 73 73 20 6c 69 73 74 ts") unless list
d6d0: 20 26 26 20 6c 69 73 74 2e 73 69 7a 65 20 3c 3d && list.size <=
d6e0: 20 36 34 0a 20 20 20 20 20 20 6c 69 73 74 2e 65 64. list.e
d6f0: 61 63 68 20 64 6f 20 7c 69 74 65 6d 7c 0a 20 20 ach do |item|.
d700: 20 20 20 20 20 20 68 61 73 68 20 3d 20 69 74 65 hash = ite
d710: 6d 2e 61 73 5f 73 3f 0a 20 20 20 20 20 20 20 20 m.as_s?.
d720: 72 61 69 73 65 20 52 65 66 75 73 65 64 2e 6e 65 raise Refused.ne
d730: 77 28 22 69 6e 76 61 6c 69 64 20 61 72 74 69 66 w("invalid artif
d740: 61 63 74 22 29 20 75 6e 6c 65 73 73 20 68 61 73 act") unless has
d750: 68 20 26 26 20 2f 5c 41 28 5b 30 2d 39 61 2d 66 h && /\A([0-9a-f
d760: 5d 7b 34 30 7d 7c 5b 30 2d 39 61 2d 66 5d 7b 36 ]{40}|[0-9a-f]{6
d770: 34 7d 29 5c 7a 2f 2e 6d 61 74 63 68 65 73 3f 28 4})\z/.matches?(
d780: 68 61 73 68 29 0a 20 20 20 20 20 20 20 20 68 61 hash). ha
d790: 73 68 65 73 20 3c 3c 20 68 61 73 68 0a 20 20 20 shes << hash.
d7a0: 20 20 20 65 6e 64 0a 20 20 20 20 65 6e 64 0a 20 end. end.
d7b0: 20 20 20 75 73 65 72 20 3d 20 6e 69 6c 0a 20 20 user = nil.
d7c0: 20 20 69 66 20 76 61 6c 75 65 20 3d 20 6f 62 6a if value = obj
d7d0: 65 63 74 5b 22 63 61 70 61 62 69 6c 69 74 69 65 ect["capabilitie
d7e0: 73 5f 6f 66 22 5d 3f 0a 20 20 20 20 20 20 75 73 s_of"]?. us
d7f0: 65 72 20 3d 20 76 61 6c 75 65 2e 61 73 5f 73 3f er = value.as_s?
d800: 0a 20 20 20 20 20 20 72 61 69 73 65 20 52 65 66 . raise Ref
d810: 75 73 65 64 2e 6e 65 77 28 22 69 6e 76 61 6c 69 used.new("invali
d820: 64 20 63 61 70 61 62 69 6c 69 74 69 65 73 5f 6f d capabilities_o
d830: 66 22 29 20 75 6e 6c 65 73 73 20 75 73 65 72 20 f") unless user
d840: 26 26 20 75 73 65 72 2e 73 69 7a 65 20 3c 3d 20 && user.size <=
d850: 31 30 30 20 26 26 20 75 73 65 72 2e 65 61 63 68 100 && user.each
d860: 5f 63 68 61 72 2e 6e 6f 6e 65 3f 28 26 2e 63 6f _char.none?(&.co
d870: 6e 74 72 6f 6c 3f 29 0a 20 20 20 20 65 6e 64 0a ntrol?). end.
d880: 20 20 20 20 52 65 71 75 65 73 74 2e 6e 65 77 28 Request.new(
d890: 68 61 73 68 65 73 2c 20 75 73 65 72 29 0a 20 20 hashes, user).
d8a0: 65 6e 64 0a 0a 20 20 63 6c 61 73 73 20 44 61 74 end.. class Dat
d8b0: 61 62 61 73 65 0a 20 20 20 20 41 52 54 49 46 41 abase. ARTIFA
d8c0: 43 54 20 20 20 20 20 20 20 20 3d 20 22 53 45 4c CT = "SEL
d8d0: 45 43 54 20 62 2e 72 69 64 2c 20 62 2e 72 63 76 ECT b.rid, b.rcv
d8e0: 69 64 2c 20 45 58 49 53 54 53 28 53 45 4c 45 43 id, EXISTS(SELEC
d8f0: 54 20 31 20 46 52 4f 4d 20 70 72 69 76 61 74 65 T 1 FROM private
d900: 20 70 20 57 48 45 52 45 20 70 2e 72 69 64 3d 62 p WHERE p.rid=b
d910: 2e 72 69 64 29 2c 20 75 2e 6c 6f 67 69 6e 2c 20 .rid), u.login,
d920: 75 2e 63 61 70 20 46 52 4f 4d 20 62 6c 6f 62 20 u.cap FROM blob
d930: 62 20 4c 45 46 54 20 4a 4f 49 4e 20 72 63 76 66 b LEFT JOIN rcvf
d940: 72 6f 6d 20 72 20 4f 4e 20 72 2e 72 63 76 69 64 rom r ON r.rcvid
d950: 3d 62 2e 72 63 76 69 64 20 4c 45 46 54 20 4a 4f =b.rcvid LEFT JO
d960: 49 4e 20 75 73 65 72 20 75 20 4f 4e 20 75 2e 75 IN user u ON u.u
d970: 69 64 3d 72 2e 75 69 64 20 57 48 45 52 45 20 62 id=r.uid WHERE b
d980: 2e 75 75 69 64 3d 3f 31 20 41 4e 44 20 62 2e 73 .uuid=?1 AND b.s
d990: 69 7a 65 3e 3d 30 22 0a 20 20 20 20 55 53 45 52 ize>=0". USER
d9a0: 20 20 20 20 20 20 20 20 20 20 20 20 3d 20 22 53 = "S
d9b0: 45 4c 45 43 54 20 63 61 70 20 46 52 4f 4d 20 75 ELECT cap FROM u
d9c0: 73 65 72 20 57 48 45 52 45 20 6c 6f 67 69 6e 3d ser WHERE login=
d9d0: 3f 31 22 0a 20 20 20 20 44 45 46 41 55 4c 54 53 ?1". DEFAULTS
d9e0: 20 20 20 20 20 20 20 20 3d 20 22 53 45 4c 45 43 = "SELEC
d9f0: 54 20 6c 6f 67 69 6e 2c 20 63 61 70 20 46 52 4f T login, cap FRO
da00: 4d 20 75 73 65 72 20 57 48 45 52 45 20 6c 6f 67 M user WHERE log
da10: 69 6e 20 49 4e 20 28 27 6e 6f 62 6f 64 79 27 2c in IN ('nobody',
da20: 27 61 6e 6f 6e 79 6d 6f 75 73 27 2c 27 72 65 61 'anonymous','rea
da30: 64 65 72 27 2c 27 64 65 76 65 6c 6f 70 65 72 27 der','developer'
da40: 29 22 0a 20 20 20 20 43 4f 4e 46 49 47 20 20 20 )". CONFIG
da50: 20 20 20 20 20 20 20 3d 20 22 53 45 4c 45 43 54 = "SELECT
da60: 20 76 61 6c 75 65 20 46 52 4f 4d 20 63 6f 6e 66 value FROM conf
da70: 69 67 20 57 48 45 52 45 20 6e 61 6d 65 3d 3f 31 ig WHERE name=?1
da80: 22 0a 20 20 20 20 45 52 52 4f 52 53 20 20 20 20 ". ERRORS
da90: 20 20 20 20 20 20 3d 20 25 77 28 4f 4b 20 45 52 = %w(OK ER
daa0: 52 4f 52 20 49 4e 54 45 52 4e 41 4c 20 50 45 52 ROR INTERNAL PER
dab0: 4d 20 41 42 4f 52 54 20 42 55 53 59 20 4c 4f 43 M ABORT BUSY LOC
dac0: 4b 45 44 20 4e 4f 4d 45 4d 20 52 45 41 44 4f 4e KED NOMEM READON
dad0: 4c 59 20 49 4e 54 45 52 52 55 50 54 20 49 4f 45 LY INTERRUPT IOE
dae0: 52 52 20 43 4f 52 52 55 50 54 20 4e 4f 54 46 4f RR CORRUPT NOTFO
daf0: 55 4e 44 20 46 55 4c 4c 20 43 41 4e 54 4f 50 45 UND FULL CANTOPE
db00: 4e 20 50 52 4f 54 4f 43 4f 4c 20 45 4d 50 54 59 N PROTOCOL EMPTY
db10: 20 53 43 48 45 4d 41 20 54 4f 4f 42 49 47 20 43 SCHEMA TOOBIG C
db20: 4f 4e 53 54 52 41 49 4e 54 20 4d 49 53 4d 41 54 ONSTRAINT MISMAT
db30: 43 48 20 4d 49 53 55 53 45 20 4e 4f 4c 46 53 20 CH MISUSE NOLFS
db40: 41 55 54 48 20 46 4f 52 4d 41 54 20 52 41 4e 47 AUTH FORMAT RANG
db50: 45 20 4e 4f 54 41 44 42 20 4e 4f 54 49 43 45 20 E NOTADB NOTICE
db60: 57 41 52 4e 49 4e 47 29 0a 20 20 20 20 52 45 41 WARNING). REA
db70: 44 4f 4e 4c 59 5f 45 52 52 4f 52 53 20 3d 20 25 DONLY_ERRORS = %
db80: 77 28 52 45 43 4f 56 45 52 59 20 43 41 4e 54 4c w(RECOVERY CANTL
db90: 4f 43 4b 20 52 4f 4c 4c 42 41 43 4b 20 44 42 4d OCK ROLLBACK DBM
dba0: 4f 56 45 44 20 43 41 4e 54 49 4e 49 54 20 44 49 OVED CANTINIT DI
dbb0: 52 45 43 54 4f 52 59 29 0a 20 20 20 20 40 64 62 RECTORY). @db
dbc0: 20 3d 20 50 6f 69 6e 74 65 72 28 56 6f 69 64 29 = Pointer(Void)
dbd0: 2e 6e 75 6c 6c 0a 0a 20 20 20 20 64 65 66 20 69 .null.. def i
dbe0: 6e 69 74 69 61 6c 69 7a 65 28 70 61 74 68 20 3a nitialize(path :
dbf0: 20 53 74 72 69 6e 67 29 0a 20 20 20 20 20 20 63 String). c
dc00: 68 65 63 6b 20 4c 69 62 53 51 4c 69 74 65 33 2e heck LibSQLite3.
dc10: 6f 70 65 6e 5f 76 32 28 22 66 69 6c 65 3a 22 20 open_v2("file:"
dc20: 2b 20 55 52 49 2e 65 6e 63 6f 64 65 5f 70 61 74 + URI.encode_pat
dc30: 68 28 70 61 74 68 29 20 2b 20 22 3f 6d 6f 64 65 h(path) + "?mode
dc40: 3d 72 6f 22 2c 20 70 6f 69 6e 74 65 72 6f 66 28 =ro", pointerof(
dc50: 40 64 62 29 2c 20 31 20 7c 20 36 34 2c 20 6e 69 @db), 1 | 64, ni
dc60: 6c 29 0a 20 20 20 20 20 20 65 78 65 63 75 74 65 l). execute
dc70: 20 22 50 52 41 47 4d 41 20 71 75 65 72 79 5f 6f "PRAGMA query_o
dc80: 6e 6c 79 3d 31 22 0a 20 20 20 20 20 20 63 68 65 nly=1". che
dc90: 63 6b 20 4c 69 62 53 51 4c 69 74 65 33 2e 62 75 ck LibSQLite3.bu
dca0: 73 79 5f 74 69 6d 65 6f 75 74 28 40 64 62 2c 20 sy_timeout(@db,
dcb0: 32 30 30 30 29 0a 20 20 20 20 20 20 65 78 65 63 2000). exec
dcc0: 75 74 65 20 22 42 45 47 49 4e 22 0a 20 20 20 20 ute "BEGIN".
dcd0: 72 65 73 63 75 65 20 65 78 0a 20 20 20 20 20 20 rescue ex.
dce0: 63 6c 6f 73 65 0a 20 20 20 20 20 20 72 61 69 73 close. rais
dcf0: 65 20 65 78 0a 20 20 20 20 65 6e 64 0a 0a 20 20 e ex. end..
dd00: 20 20 64 65 66 20 63 68 65 63 6b 28 63 6f 64 65 def check(code
dd10: 20 3a 20 49 6e 74 33 32 29 20 3a 20 4e 69 6c 0a : Int32) : Nil.
dd20: 20 20 20 20 20 20 72 65 74 75 72 6e 20 69 66 20 return if
dd30: 63 6f 64 65 20 3d 3d 20 30 0a 20 20 20 20 20 20 code == 0.
dd40: 65 78 74 65 6e 64 65 64 20 3d 20 4c 69 62 53 51 extended = LibSQ
dd50: 4c 69 74 65 33 2e 65 78 74 65 6e 64 65 64 5f 65 Lite3.extended_e
dd60: 72 72 63 6f 64 65 28 40 64 62 29 0a 20 20 20 20 rrcode(@db).
dd70: 20 20 62 61 73 65 20 3d 20 65 78 74 65 6e 64 65 base = extende
dd80: 64 20 26 20 32 35 35 0a 20 20 20 20 20 20 6e 61 d & 255. na
dd90: 6d 65 20 3d 20 22 53 51 4c 49 54 45 5f 22 20 2b me = "SQLITE_" +
dda0: 20 28 45 52 52 4f 52 53 5b 62 61 73 65 5d 3f 20 (ERRORS[base]?
ddb0: 7c 7c 20 22 45 52 52 4f 52 22 29 0a 20 20 20 20 || "ERROR").
ddc0: 20 20 69 66 20 62 61 73 65 20 3d 3d 20 38 20 26 if base == 8 &
ddd0: 26 20 28 73 75 66 66 69 78 20 3d 20 52 45 41 44 & (suffix = READ
dde0: 4f 4e 4c 59 5f 45 52 52 4f 52 53 5b 28 65 78 74 ONLY_ERRORS[(ext
ddf0: 65 6e 64 65 64 20 3e 3e 20 38 29 20 2d 20 31 5d ended >> 8) - 1]
de00: 3f 29 20 26 26 20 65 78 74 65 6e 64 65 64 20 3e ?) && extended >
de10: 20 32 35 35 0a 20 20 20 20 20 20 20 20 6e 61 6d 255. nam
de20: 65 20 2b 3d 20 22 5f 22 20 2b 20 73 75 66 66 69 e += "_" + suffi
de30: 78 0a 20 20 20 20 20 20 65 6e 64 0a 20 20 20 20 x. end.
de40: 20 20 72 61 69 73 65 20 55 6e 61 76 61 69 6c 61 raise Unavaila
de50: 62 6c 65 2e 6e 65 77 28 22 23 7b 6e 61 6d 65 7d ble.new("#{name}
de60: 20 28 23 7b 65 78 74 65 6e 64 65 64 7d 29 3a 20 (#{extended}):
de70: 23 7b 53 74 72 69 6e 67 2e 6e 65 77 28 4c 69 62 #{String.new(Lib
de80: 53 51 4c 69 74 65 33 2e 65 72 72 6d 73 67 28 40 SQLite3.errmsg(@
de90: 64 62 29 29 7d 22 29 0a 20 20 20 20 65 6e 64 0a db))}"). end.
dea0: 0a 20 20 20 20 64 65 66 20 65 78 65 63 75 74 65 . def execute
deb0: 28 73 71 6c 20 3a 20 53 74 72 69 6e 67 29 20 3a (sql : String) :
dec0: 20 4e 69 6c 0a 20 20 20 20 20 20 63 68 65 63 6b Nil. check
ded0: 20 4c 69 62 53 51 4c 69 74 65 33 2e 65 78 65 63 LibSQLite3.exec
dee0: 28 40 64 62 2c 20 73 71 6c 2c 20 6e 69 6c 2c 20 (@db, sql, nil,
def0: 6e 69 6c 2c 20 6e 69 6c 29 0a 20 20 20 20 65 6e nil, nil). en
df00: 64 0a 0a 20 20 20 20 64 65 66 20 72 6f 77 73 28 d.. def rows(
df10: 73 71 6c 20 3a 20 53 74 72 69 6e 67 2c 20 76 61 sql : String, va
df20: 6c 75 65 20 3a 20 53 74 72 69 6e 67 3f 20 3d 20 lue : String? =
df30: 6e 69 6c 2c 20 26 62 6c 6f 63 6b 20 3a 20 50 6f nil, &block : Po
df40: 69 6e 74 65 72 28 56 6f 69 64 29 20 2d 3e 29 20 inter(Void) ->)
df50: 3a 20 4e 69 6c 0a 20 20 20 20 20 20 73 74 61 74 : Nil. stat
df60: 65 6d 65 6e 74 20 3d 20 50 6f 69 6e 74 65 72 28 ement = Pointer(
df70: 56 6f 69 64 29 2e 6e 75 6c 6c 0a 20 20 20 20 20 Void).null.
df80: 20 62 65 67 69 6e 0a 20 20 20 20 20 20 20 20 63 begin. c
df90: 68 65 63 6b 20 4c 69 62 53 51 4c 69 74 65 33 2e heck LibSQLite3.
dfa0: 70 72 65 70 61 72 65 5f 76 32 28 40 64 62 2c 20 prepare_v2(@db,
dfb0: 73 71 6c 2c 20 2d 31 2c 20 70 6f 69 6e 74 65 72 sql, -1, pointer
dfc0: 6f 66 28 73 74 61 74 65 6d 65 6e 74 29 2c 20 6e of(statement), n
dfd0: 69 6c 29 0a 20 20 20 20 20 20 20 20 63 68 65 63 il). chec
dfe0: 6b 20 4c 69 62 53 51 4c 69 74 65 33 2e 62 69 6e k LibSQLite3.bin
dff0: 64 5f 74 65 78 74 28 73 74 61 74 65 6d 65 6e 74 d_text(statement
e000: 2c 20 31 2c 20 76 61 6c 75 65 2c 20 76 61 6c 75 , 1, value, valu
e010: 65 2e 62 79 74 65 73 69 7a 65 2c 20 50 6f 69 6e e.bytesize, Poin
e020: 74 65 72 28 56 6f 69 64 29 2e 6e 65 77 28 55 49 ter(Void).new(UI
e030: 6e 74 36 34 3a 3a 4d 41 58 29 29 20 69 66 20 76 nt64::MAX)) if v
e040: 61 6c 75 65 0a 20 20 20 20 20 20 20 20 6c 6f 6f alue. loo
e050: 70 20 64 6f 0a 20 20 20 20 20 20 20 20 20 20 63 p do. c
e060: 6f 64 65 20 3d 20 4c 69 62 53 51 4c 69 74 65 33 ode = LibSQLite3
e070: 2e 73 74 65 70 28 73 74 61 74 65 6d 65 6e 74 29 .step(statement)
e080: 0a 20 20 20 20 20 20 20 20 20 20 62 72 65 61 6b . break
e090: 20 69 66 20 63 6f 64 65 20 3d 3d 20 31 30 31 0a if code == 101.
e0a0: 20 20 20 20 20 20 20 20 20 20 63 68 65 63 6b 20 check
e0b0: 63 6f 64 65 20 75 6e 6c 65 73 73 20 63 6f 64 65 code unless code
e0c0: 20 3d 3d 20 31 30 30 0a 20 20 20 20 20 20 20 20 == 100.
e0d0: 20 20 79 69 65 6c 64 20 73 74 61 74 65 6d 65 6e yield statemen
e0e0: 74 0a 20 20 20 20 20 20 20 20 65 6e 64 0a 20 20 t. end.
e0f0: 20 20 20 20 65 6e 73 75 72 65 0a 20 20 20 20 20 ensure.
e100: 20 20 20 4c 69 62 53 51 4c 69 74 65 33 2e 66 69 LibSQLite3.fi
e110: 6e 61 6c 69 7a 65 28 73 74 61 74 65 6d 65 6e 74 nalize(statement
e120: 29 20 75 6e 6c 65 73 73 20 73 74 61 74 65 6d 65 ) unless stateme
e130: 6e 74 2e 6e 75 6c 6c 3f 0a 20 20 20 20 20 20 65 nt.null?. e
e140: 6e 64 0a 20 20 20 20 65 6e 64 0a 0a 20 20 20 20 nd. end..
e150: 64 65 66 20 74 65 78 74 28 73 74 61 74 65 6d 65 def text(stateme
e160: 6e 74 20 3a 20 50 6f 69 6e 74 65 72 28 56 6f 69 nt : Pointer(Voi
e170: 64 29 2c 20 63 6f 6c 75 6d 6e 20 3a 20 49 6e 74 d), column : Int
e180: 33 32 29 20 3a 20 53 74 72 69 6e 67 3f 0a 20 20 32) : String?.
e190: 20 20 20 20 53 74 72 69 6e 67 2e 6e 65 77 28 4c String.new(L
e1a0: 69 62 53 51 4c 69 74 65 33 2e 63 6f 6c 75 6d 6e ibSQLite3.column
e1b0: 5f 74 65 78 74 28 73 74 61 74 65 6d 65 6e 74 2c _text(statement,
e1c0: 20 63 6f 6c 75 6d 6e 29 29 20 75 6e 6c 65 73 73 column)) unless
e1d0: 20 4c 69 62 53 51 4c 69 74 65 33 2e 63 6f 6c 75 LibSQLite3.colu
e1e0: 6d 6e 5f 74 79 70 65 28 73 74 61 74 65 6d 65 6e mn_type(statemen
e1f0: 74 2c 20 63 6f 6c 75 6d 6e 29 20 3d 3d 20 35 0a t, column) == 5.
e200: 20 20 20 20 65 6e 64 0a 0a 20 20 20 20 64 65 66 end.. def
e210: 20 65 78 70 61 6e 64 65 64 28 63 61 70 20 3a 20 expanded(cap :
e220: 53 74 72 69 6e 67 2c 20 64 65 66 61 75 6c 74 73 String, defaults
e230: 20 3a 20 48 61 73 68 28 53 74 72 69 6e 67 2c 20 : Hash(String,
e240: 53 74 72 69 6e 67 29 29 20 3a 20 53 74 72 69 6e String)) : Strin
e250: 67 0a 20 20 20 20 20 20 63 61 70 73 20 3d 20 53 g. caps = S
e260: 65 74 28 43 68 61 72 29 2e 6e 65 77 0a 20 20 20 et(Char).new.
e270: 20 20 20 61 64 64 20 3d 20 2d 3e 28 76 61 6c 75 add = ->(valu
e280: 65 20 3a 20 53 74 72 69 6e 67 29 20 7b 20 76 61 e : String) { va
e290: 6c 75 65 2e 65 61 63 68 5f 63 68 61 72 20 7b 20 lue.each_char {
e2a0: 7c 63 68 61 72 7c 20 63 61 70 73 20 3c 3c 20 63 |char| caps << c
e2b0: 68 61 72 20 69 66 20 27 30 27 20 3c 3d 20 63 68 har if '0' <= ch
e2c0: 61 72 20 3c 3d 20 27 7a 27 20 7d 20 7d 0a 20 20 ar <= 'z' } }.
e2d0: 20 20 20 20 61 64 64 2e 63 61 6c 6c 28 63 61 70 add.call(cap
e2e0: 29 0a 20 20 20 20 20 20 61 64 64 2e 63 61 6c 6c ). add.call
e2f0: 28 64 65 66 61 75 6c 74 73 5b 22 61 6e 6f 6e 79 (defaults["anony
e300: 6d 6f 75 73 22 5d 3f 20 7c 7c 20 22 22 29 0a 20 mous"]? || "").
e310: 20 20 20 20 20 61 64 64 2e 63 61 6c 6c 28 64 65 add.call(de
e320: 66 61 75 6c 74 73 5b 22 6e 6f 62 6f 64 79 22 5d faults["nobody"]
e330: 3f 20 7c 7c 20 22 22 29 0a 20 20 20 20 20 20 61 ? || ""). a
e340: 64 64 2e 63 61 6c 6c 28 22 62 63 64 65 66 67 68 dd.call("bcdefgh
e350: 69 6a 6b 6c 6d 6e 6f 70 71 72 74 77 7a 32 33 34 ijklmnopqrtwz234
e360: 35 36 37 41 44 22 29 20 69 66 20 63 61 70 73 2e 567AD") if caps.
e370: 69 6e 63 6c 75 64 65 73 3f 28 27 61 27 29 20 7c includes?('a') |
e380: 7c 20 63 61 70 73 2e 69 6e 63 6c 75 64 65 73 3f | caps.includes?
e390: 28 27 73 27 29 0a 20 20 20 20 20 20 64 65 76 65 ('s'). deve
e3a0: 6c 6f 70 65 72 20 3d 20 63 61 70 73 2e 69 6e 63 loper = caps.inc
e3b0: 6c 75 64 65 73 3f 28 27 76 27 29 0a 20 20 20 20 ludes?('v').
e3c0: 20 20 61 64 64 2e 63 61 6c 6c 28 64 65 66 61 75 add.call(defau
e3d0: 6c 74 73 5b 22 64 65 76 65 6c 6f 70 65 72 22 5d lts["developer"]
e3e0: 3f 20 7c 7c 20 22 22 29 20 69 66 20 64 65 76 65 ? || "") if deve
e3f0: 6c 6f 70 65 72 0a 20 20 20 20 20 20 69 66 20 63 loper. if c
e400: 61 70 73 2e 69 6e 63 6c 75 64 65 73 3f 28 27 75 aps.includes?('u
e410: 27 29 0a 20 20 20 20 20 20 20 20 61 64 64 2e 63 '). add.c
e420: 61 6c 6c 28 64 65 66 61 75 6c 74 73 5b 22 72 65 all(defaults["re
e430: 61 64 65 72 22 5d 3f 20 7c 7c 20 22 22 29 0a 20 ader"]? || "").
e440: 20 20 20 20 20 20 20 61 64 64 2e 63 61 6c 6c 28 add.call(
e450: 64 65 66 61 75 6c 74 73 5b 22 64 65 76 65 6c 6f defaults["develo
e460: 70 65 72 22 5d 3f 20 7c 7c 20 22 22 29 20 69 66 per"]? || "") if
e470: 20 63 61 70 73 2e 69 6e 63 6c 75 64 65 73 3f 28 caps.includes?(
e480: 27 76 27 29 20 26 26 20 21 64 65 76 65 6c 6f 70 'v') && !develop
e490: 65 72 0a 20 20 20 20 20 20 65 6e 64 0a 20 20 20 er. end.
e4a0: 20 20 20 28 28 27 61 27 2e 2e 27 7a 27 29 2e 74 (('a'..'z').t
e4b0: 6f 5f 61 20 2b 20 28 27 30 27 2e 2e 27 39 27 29 o_a + ('0'..'9')
e4c0: 2e 74 6f 5f 61 20 2b 20 28 27 41 27 2e 2e 27 5a .to_a + ('A'..'Z
e4d0: 27 29 2e 74 6f 5f 61 29 2e 73 65 6c 65 63 74 20 ').to_a).select
e4e0: 7b 20 7c 63 68 61 72 7c 20 63 61 70 73 2e 69 6e { |char| caps.in
e4f0: 63 6c 75 64 65 73 3f 28 63 68 61 72 29 20 7d 2e cludes?(char) }.
e500: 6a 6f 69 6e 0a 20 20 20 20 65 6e 64 0a 0a 20 20 join. end..
e510: 20 20 64 65 66 20 6d 6f 64 65 72 61 74 65 64 28 def moderated(
e520: 6e 61 6d 65 20 3a 20 53 74 72 69 6e 67 2c 20 63 name : String, c
e530: 61 70 73 20 3a 20 53 74 72 69 6e 67 2c 20 70 65 aps : String, pe
e540: 72 6d 69 73 73 69 6f 6e 20 3a 20 43 68 61 72 29 rmission : Char)
e550: 20 3a 20 42 6f 6f 6c 0a 20 20 20 20 20 20 74 72 : Bool. tr
e560: 75 74 68 20 3d 20 66 61 6c 73 65 0a 20 20 20 20 uth = false.
e570: 20 20 72 6f 77 73 28 43 4f 4e 46 49 47 2c 20 6e rows(CONFIG, n
e580: 61 6d 65 29 20 7b 20 7c 72 6f 77 7c 20 74 72 75 ame) { |row| tru
e590: 74 68 20 3d 20 7b 22 6f 6e 22 2c 20 22 79 65 73 th = {"on", "yes
e5a0: 22 2c 20 22 74 72 75 65 22 2c 20 22 31 22 7d 2e ", "true", "1"}.
e5b0: 69 6e 63 6c 75 64 65 73 3f 28 28 74 65 78 74 28 includes?((text(
e5c0: 72 6f 77 2c 20 30 29 20 7c 7c 20 22 22 29 2e 64 row, 0) || "").d
e5d0: 6f 77 6e 63 61 73 65 29 20 7d 0a 20 20 20 20 20 owncase) }.
e5e0: 20 74 72 75 74 68 20 26 26 20 21 63 61 70 73 2e truth && !caps.
e5f0: 69 6e 63 6c 75 64 65 73 3f 28 70 65 72 6d 69 73 includes?(permis
e600: 73 69 6f 6e 29 0a 20 20 20 20 65 6e 64 0a 0a 20 sion). end..
e610: 20 20 20 64 65 66 20 61 6e 73 77 65 72 28 69 64 def answer(id
e620: 65 6e 74 69 74 79 20 3a 20 49 64 65 6e 74 69 74 entity : Identit
e630: 79 2c 20 72 65 71 75 65 73 74 20 3a 20 52 65 71 y, request : Req
e640: 75 65 73 74 29 20 3a 20 41 6e 73 77 65 72 0a 20 uest) : Answer.
e650: 20 20 20 20 20 64 65 66 61 75 6c 74 73 20 3d 20 defaults =
e660: 7b 7d 20 6f 66 20 53 74 72 69 6e 67 20 3d 3e 20 {} of String =>
e670: 53 74 72 69 6e 67 0a 20 20 20 20 20 20 72 6f 77 String. row
e680: 73 28 44 45 46 41 55 4c 54 53 29 20 7b 20 7c 72 s(DEFAULTS) { |r
e690: 6f 77 7c 20 64 65 66 61 75 6c 74 73 5b 74 65 78 ow| defaults[tex
e6a0: 74 28 72 6f 77 2c 20 30 29 2e 6e 6f 74 5f 6e 69 t(row, 0).not_ni
e6b0: 6c 21 5d 20 3d 20 74 65 78 74 28 72 6f 77 2c 20 l!] = text(row,
e6c0: 31 29 20 7c 7c 20 22 22 20 7d 0a 20 20 20 20 20 1) || "" }.
e6d0: 20 61 72 74 69 66 61 63 74 73 20 3d 20 72 65 71 artifacts = req
e6e0: 75 65 73 74 2e 61 72 74 69 66 61 63 74 73 2e 6d uest.artifacts.m
e6f0: 61 70 20 64 6f 20 7c 68 61 73 68 7c 0a 20 20 20 ap do |hash|.
e700: 20 20 20 20 20 61 72 74 69 66 61 63 74 20 3d 20 artifact =
e710: 41 72 74 69 66 61 63 74 2e 6e 65 77 28 68 61 73 Artifact.new(has
e720: 68 29 0a 20 20 20 20 20 20 20 20 72 6f 77 73 28 h). rows(
e730: 41 52 54 49 46 41 43 54 2c 20 68 61 73 68 29 20 ARTIFACT, hash)
e740: 64 6f 20 7c 72 6f 77 7c 0a 20 20 20 20 20 20 20 do |row|.
e750: 20 20 20 6e 65 78 74 20 69 66 20 4c 69 62 53 51 next if LibSQ
e760: 4c 69 74 65 33 2e 63 6f 6c 75 6d 6e 5f 69 6e 74 Lite3.column_int
e770: 36 34 28 72 6f 77 2c 20 32 29 20 21 3d 20 30 20 64(row, 2) != 0
e780: 26 26 20 21 69 64 65 6e 74 69 74 79 2e 63 61 70 && !identity.cap
e790: 61 62 69 6c 69 74 69 65 73 2e 69 6e 63 6c 75 64 abilities.includ
e7a0: 65 73 3f 28 27 78 27 29 0a 20 20 20 20 20 20 20 es?('x').
e7b0: 20 20 20 73 65 6e 64 65 72 20 3d 20 74 65 78 74 sender = text
e7c0: 28 72 6f 77 2c 20 33 29 0a 20 20 20 20 20 20 20 (row, 3).
e7d0: 20 20 20 61 72 74 69 66 61 63 74 20 3d 20 41 72 artifact = Ar
e7e0: 74 69 66 61 63 74 2e 6e 65 77 28 61 72 74 69 66 tifact.new(artif
e7f0: 61 63 74 3a 20 68 61 73 68 2c 20 72 65 63 65 69 act: hash, recei
e800: 76 65 64 3a 20 74 72 75 65 2c 20 73 65 6e 64 65 ved: true, sende
e810: 72 3a 20 73 65 6e 64 65 72 2c 0a 20 20 20 20 20 r: sender,.
e820: 20 20 20 20 20 20 20 63 61 70 61 62 69 6c 69 74 capabilit
e830: 69 65 73 3a 20 73 65 6e 64 65 72 20 3f 20 65 78 ies: sender ? ex
e840: 70 61 6e 64 65 64 28 74 65 78 74 28 72 6f 77 2c panded(text(row,
e850: 20 34 29 20 7c 7c 20 22 22 2c 20 64 65 66 61 75 4) || "", defau
e860: 6c 74 73 29 20 3a 20 6e 69 6c 2c 0a 20 20 20 20 lts) : nil,.
e870: 20 20 20 20 20 20 20 20 72 65 63 65 69 70 74 3a receipt:
e880: 20 4c 69 62 53 51 4c 69 74 65 33 2e 63 6f 6c 75 LibSQLite3.colu
e890: 6d 6e 5f 69 6e 74 36 34 28 72 6f 77 2c 20 31 29 mn_int64(row, 1)
e8a0: 2c 20 72 69 64 3a 20 4c 69 62 53 51 4c 69 74 65 , rid: LibSQLite
e8b0: 33 2e 63 6f 6c 75 6d 6e 5f 69 6e 74 36 34 28 72 3.column_int64(r
e8c0: 6f 77 2c 20 30 29 29 0a 20 20 20 20 20 20 20 20 ow, 0)).
e8d0: 65 6e 64 0a 20 20 20 20 20 20 20 20 61 72 74 69 end. arti
e8e0: 66 61 63 74 0a 20 20 20 20 20 20 65 6e 64 0a 20 fact. end.
e8f0: 20 20 20 20 20 75 73 65 72 20 3d 20 6e 69 6c 0a user = nil.
e900: 20 20 20 20 20 20 69 66 20 6e 61 6d 65 20 3d 20 if name =
e910: 72 65 71 75 65 73 74 2e 63 61 70 61 62 69 6c 69 request.capabili
e920: 74 69 65 73 5f 6f 66 0a 20 20 20 20 20 20 20 20 ties_of.
e930: 75 73 65 72 20 3d 20 55 73 65 72 2e 6e 65 77 28 user = User.new(
e940: 6e 61 6d 65 29 0a 20 20 20 20 20 20 20 20 72 6f name). ro
e950: 77 73 28 55 53 45 52 2c 20 6e 61 6d 65 29 20 64 ws(USER, name) d
e960: 6f 20 7c 72 6f 77 7c 0a 20 20 20 20 20 20 20 20 o |row|.
e970: 20 20 63 61 70 73 20 3d 20 65 78 70 61 6e 64 65 caps = expande
e980: 64 28 74 65 78 74 28 72 6f 77 2c 20 30 29 20 7c d(text(row, 0) |
e990: 7c 20 22 22 2c 20 64 65 66 61 75 6c 74 73 29 0a | "", defaults).
e9a0: 20 20 20 20 20 20 20 20 20 20 75 73 65 72 20 3d user =
e9b0: 20 55 73 65 72 2e 6e 65 77 28 6e 61 6d 65 2c 20 User.new(name,
e9c0: 63 61 70 73 2c 20 6d 6f 64 65 72 61 74 65 64 28 caps, moderated(
e9d0: 22 6d 6f 64 72 65 71 2d 77 69 6b 69 22 2c 20 63 "modreq-wiki", c
e9e0: 61 70 73 2c 20 27 6c 27 29 2c 20 6d 6f 64 65 72 aps, 'l'), moder
e9f0: 61 74 65 64 28 22 6d 6f 64 72 65 71 2d 74 6b 74 ated("modreq-tkt
ea00: 22 2c 20 63 61 70 73 2c 20 27 71 27 29 29 0a 20 ", caps, 'q')).
ea10: 20 20 20 20 20 20 20 65 6e 64 0a 20 20 20 20 20 end.
ea20: 20 65 6e 64 0a 20 20 20 20 20 20 65 78 65 63 75 end. execu
ea30: 74 65 20 22 43 4f 4d 4d 49 54 22 0a 20 20 20 20 te "COMMIT".
ea40: 20 20 41 6e 73 77 65 72 2e 6e 65 77 28 61 72 74 Answer.new(art
ea50: 69 66 61 63 74 73 2c 20 75 73 65 72 29 0a 20 20 ifacts, user).
ea60: 20 20 65 6e 64 0a 0a 20 20 20 20 64 65 66 20 63 end.. def c
ea70: 6c 6f 73 65 20 3a 20 4e 69 6c 0a 20 20 20 20 20 lose : Nil.
ea80: 20 4c 69 62 53 51 4c 69 74 65 33 2e 63 6c 6f 73 LibSQLite3.clos
ea90: 65 5f 76 32 28 40 64 62 29 20 75 6e 6c 65 73 73 e_v2(@db) unless
eaa0: 20 40 64 62 2e 6e 75 6c 6c 3f 0a 20 20 20 20 20 @db.null?.
eab0: 20 40 64 62 20 3d 20 50 6f 69 6e 74 65 72 28 56 @db = Pointer(V
eac0: 6f 69 64 29 2e 6e 75 6c 6c 0a 20 20 20 20 65 6e oid).null. en
ead0: 64 0a 20 20 65 6e 64 0a 0a 20 20 64 65 66 20 73 d. end.. def s
eae0: 65 6c 66 2e 6c 69 6e 65 28 73 6f 63 6b 65 74 20 elf.line(socket
eaf0: 3a 20 55 4e 49 58 53 6f 63 6b 65 74 2c 20 6c 69 : UNIXSocket, li
eb00: 6d 69 74 20 3a 20 49 6e 74 33 32 2c 20 64 65 61 mit : Int32, dea
eb10: 64 6c 69 6e 65 20 3a 20 54 69 6d 65 29 20 3a 20 dline : Time) :
eb20: 53 74 72 69 6e 67 0a 20 20 20 20 62 79 74 65 73 String. bytes
eb30: 20 3d 20 49 4f 3a 3a 4d 65 6d 6f 72 79 2e 6e 65 = IO::Memory.ne
eb40: 77 0a 20 20 20 20 6c 6f 6f 70 20 64 6f 0a 20 20 w. loop do.
eb50: 20 20 20 20 72 65 6d 61 69 6e 69 6e 67 20 3d 20 remaining =
eb60: 64 65 61 64 6c 69 6e 65 20 2d 20 54 69 6d 65 2e deadline - Time.
eb70: 75 74 63 0a 20 20 20 20 20 20 72 61 69 73 65 20 utc. raise
eb80: 49 4f 3a 3a 54 69 6d 65 6f 75 74 45 72 72 6f 72 IO::TimeoutError
eb90: 2e 6e 65 77 28 22 64 65 61 64 6c 69 6e 65 22 29 .new("deadline")
eba0: 20 69 66 20 72 65 6d 61 69 6e 69 6e 67 20 3c 3d if remaining <=
ebb0: 20 54 69 6d 65 3a 3a 53 70 61 6e 2e 7a 65 72 6f Time::Span.zero
ebc0: 0a 20 20 20 20 20 20 73 6f 63 6b 65 74 2e 72 65 . socket.re
ebd0: 61 64 5f 74 69 6d 65 6f 75 74 20 3d 20 72 65 6d ad_timeout = rem
ebe0: 61 69 6e 69 6e 67 0a 20 20 20 20 20 20 62 79 74 aining. byt
ebf0: 65 20 3d 20 73 6f 63 6b 65 74 2e 72 65 61 64 5f e = socket.read_
ec00: 62 79 74 65 0a 20 20 20 20 20 20 72 61 69 73 65 byte. raise
ec10: 20 52 65 66 75 73 65 64 2e 6e 65 77 28 22 65 78 Refused.new("ex
ec20: 70 65 63 74 65 64 20 74 77 6f 20 4a 53 4f 4e 20 pected two JSON
ec30: 6c 69 6e 65 73 22 29 20 75 6e 6c 65 73 73 20 62 lines") unless b
ec40: 79 74 65 0a 20 20 20 20 20 20 62 72 65 61 6b 20 yte. break
ec50: 69 66 20 62 79 74 65 20 3d 3d 20 31 30 0a 20 20 if byte == 10.
ec60: 20 20 20 20 72 61 69 73 65 20 52 65 66 75 73 65 raise Refuse
ec70: 64 2e 6e 65 77 28 22 6c 69 6e 65 20 74 6f 6f 20 d.new("line too
ec80: 6c 6f 6e 67 22 29 20 69 66 20 62 79 74 65 73 2e long") if bytes.
ec90: 73 69 7a 65 20 3e 3d 20 6c 69 6d 69 74 0a 20 20 size >= limit.
eca0: 20 20 20 20 62 79 74 65 73 2e 77 72 69 74 65 5f bytes.write_
ecb0: 62 79 74 65 28 62 79 74 65 29 0a 20 20 20 20 65 byte(byte). e
ecc0: 6e 64 0a 20 20 20 20 62 79 74 65 73 2e 74 6f 5f nd. bytes.to_
ecd0: 73 0a 20 20 72 65 73 63 75 65 20 49 4f 3a 3a 54 s. rescue IO::T
ece0: 69 6d 65 6f 75 74 45 72 72 6f 72 0a 20 20 20 20 imeoutError.
ecf0: 72 61 69 73 65 20 52 65 66 75 73 65 64 2e 6e 65 raise Refused.ne
ed00: 77 28 22 72 65 71 75 65 73 74 20 6e 6f 74 20 72 w("request not r
ed10: 65 63 65 69 76 65 64 20 77 69 74 68 69 6e 20 32 eceived within 2
ed20: 20 73 22 29 0a 20 20 65 6e 64 0a 0a 20 20 64 65 s"). end.. de
ed30: 66 20 73 65 6c 66 2e 73 65 72 76 65 28 73 6f 63 f self.serve(soc
ed40: 6b 65 74 20 3a 20 55 4e 49 58 53 6f 63 6b 65 74 ket : UNIXSocket
ed50: 2c 20 72 65 70 6f 73 69 74 6f 72 69 65 73 20 3a , repositories :
ed60: 20 53 74 72 69 6e 67 2c 20 73 74 61 72 74 65 64 String, started
ed70: 20 3a 20 54 69 6d 65 2c 20 62 75 73 79 20 3a 20 : Time, busy :
ed80: 42 6f 6f 6c 29 20 3a 20 4e 69 6c 0a 20 20 20 20 Bool) : Nil.
ed90: 72 65 70 6f 73 69 74 6f 72 79 20 3d 20 22 2d 22 repository = "-"
eda0: 0a 20 20 20 20 63 6f 75 6e 74 20 3d 20 30 0a 20 . count = 0.
edb0: 20 20 20 6f 75 74 63 6f 6d 65 20 3d 20 22 72 65 outcome = "re
edc0: 66 75 73 65 64 22 0a 20 20 20 20 73 6f 63 6b 65 fused". socke
edd0: 74 2e 77 72 69 74 65 5f 74 69 6d 65 6f 75 74 20 t.write_timeout
ede0: 3d 20 32 2e 73 65 63 6f 6e 64 73 0a 20 20 20 20 = 2.seconds.
edf0: 63 72 65 64 65 6e 74 69 61 6c 73 20 3d 20 52 65 credentials = Re
ee00: 63 65 69 70 74 50 65 65 72 3a 3a 43 72 65 64 65 ceiptPeer::Crede
ee10: 6e 74 69 61 6c 73 2e 6e 65 77 0a 20 20 20 20 73 ntials.new. s
ee20: 69 7a 65 20 3d 20 73 69 7a 65 6f 66 28 52 65 63 ize = sizeof(Rec
ee30: 65 69 70 74 50 65 65 72 3a 3a 43 72 65 64 65 6e eiptPeer::Creden
ee40: 74 69 61 6c 73 29 2e 74 6f 5f 75 33 32 0a 20 20 tials).to_u32.
ee50: 20 20 69 66 20 52 65 63 65 69 70 74 50 65 65 72 if ReceiptPeer
ee60: 2e 67 65 74 73 6f 63 6b 6f 70 74 28 73 6f 63 6b .getsockopt(sock
ee70: 65 74 2e 66 64 2c 20 31 2c 20 31 37 2c 20 70 6f et.fd, 1, 17, po
ee80: 69 6e 74 65 72 6f 66 28 63 72 65 64 65 6e 74 69 interof(credenti
ee90: 61 6c 73 29 2c 20 70 6f 69 6e 74 65 72 6f 66 28 als), pointerof(
eea0: 73 69 7a 65 29 29 20 21 3d 20 30 20 7c 7c 20 73 size)) != 0 || s
eeb0: 69 7a 65 20 21 3d 20 73 69 7a 65 6f 66 28 52 65 ize != sizeof(Re
eec0: 63 65 69 70 74 50 65 65 72 3a 3a 43 72 65 64 65 ceiptPeer::Crede
eed0: 6e 74 69 61 6c 73 29 20 7c 7c 20 63 72 65 64 65 ntials) || crede
eee0: 6e 74 69 61 6c 73 2e 75 69 64 20 21 3d 20 4c 69 ntials.uid != Li
eef0: 62 43 2e 67 65 74 75 69 64 0a 20 20 20 20 20 20 bC.getuid.
ef00: 72 61 69 73 65 20 52 65 66 75 73 65 64 2e 6e 65 raise Refused.ne
ef10: 77 28 22 70 65 65 72 20 75 69 64 20 64 69 66 66 w("peer uid diff
ef20: 65 72 73 22 29 0a 20 20 20 20 65 6e 64 0a 20 20 ers"). end.
ef30: 20 20 69 66 20 62 75 73 79 0a 20 20 20 20 20 20 if busy.
ef40: 6f 75 74 63 6f 6d 65 20 3d 20 22 62 75 73 79 22 outcome = "busy"
ef50: 0a 20 20 20 20 20 20 73 6f 63 6b 65 74 2e 70 75 . socket.pu
ef60: 74 73 28 7b 75 6e 61 76 61 69 6c 61 62 6c 65 3a ts({unavailable:
ef70: 20 22 62 75 73 79 22 2c 20 72 65 74 72 79 5f 61 "busy", retry_a
ef80: 66 74 65 72 3a 20 31 7d 2e 74 6f 5f 6a 73 6f 6e fter: 1}.to_json
ef90: 29 0a 20 20 20 20 20 20 72 65 74 75 72 6e 0a 20 ). return.
efa0: 20 20 20 65 6e 64 0a 20 20 20 20 69 64 65 6e 74 end. ident
efb0: 69 74 79 20 3d 20 69 64 65 6e 74 69 74 79 28 6c ity = identity(l
efc0: 69 6e 65 28 73 6f 63 6b 65 74 2c 20 31 30 32 34 ine(socket, 1024
efd0: 2c 20 73 74 61 72 74 65 64 20 2b 20 32 2e 73 65 , started + 2.se
efe0: 63 6f 6e 64 73 29 2c 20 72 65 70 6f 73 69 74 6f conds), reposito
eff0: 72 69 65 73 29 0a 20 20 20 20 72 65 70 6f 73 69 ries). reposi
f000: 74 6f 72 79 20 3d 20 69 64 65 6e 74 69 74 79 2e tory = identity.
f010: 72 65 70 6f 73 69 74 6f 72 79 0a 20 20 20 20 72 repository. r
f020: 65 71 75 65 73 74 20 3d 20 72 65 71 75 65 73 74 equest = request
f030: 28 6c 69 6e 65 28 73 6f 63 6b 65 74 2c 20 38 31 (line(socket, 81
f040: 39 32 2c 20 73 74 61 72 74 65 64 20 2b 20 32 2e 92, started + 2.
f050: 73 65 63 6f 6e 64 73 29 29 0a 20 20 20 20 63 6f seconds)). co
f060: 75 6e 74 20 3d 20 72 65 71 75 65 73 74 2e 61 72 unt = request.ar
f070: 74 69 66 61 63 74 73 2e 73 69 7a 65 0a 20 20 20 tifacts.size.
f080: 20 69 66 20 69 64 65 6e 74 69 74 79 2e 63 61 70 if identity.cap
f090: 61 62 69 6c 69 74 69 65 73 2e 69 6e 63 6c 75 64 abilities.includ
f0a0: 65 73 3f 28 27 6f 27 29 0a 20 20 20 20 20 20 64 es?('o'). d
f0b0: 62 20 3d 20 44 61 74 61 62 61 73 65 2e 6e 65 77 b = Database.new
f0c0: 28 46 69 6c 65 2e 6a 6f 69 6e 28 72 65 70 6f 73 (File.join(repos
f0d0: 69 74 6f 72 69 65 73 2c 20 72 65 70 6f 73 69 74 itories, reposit
f0e0: 6f 72 79 20 2b 20 22 2e 66 6f 73 73 69 6c 22 29 ory + ".fossil")
f0f0: 29 0a 20 20 20 20 20 20 62 65 67 69 6e 0a 20 20 ). begin.
f100: 20 20 20 20 20 20 61 6e 73 77 65 72 20 3d 20 64 answer = d
f110: 62 2e 61 6e 73 77 65 72 28 69 64 65 6e 74 69 74 b.answer(identit
f120: 79 2c 20 72 65 71 75 65 73 74 29 0a 20 20 20 20 y, request).
f130: 20 20 65 6e 73 75 72 65 0a 20 20 20 20 20 20 20 ensure.
f140: 20 64 62 2e 63 6c 6f 73 65 0a 20 20 20 20 20 20 db.close.
f150: 65 6e 64 0a 20 20 20 20 65 6c 73 65 0a 20 20 20 end. else.
f160: 20 20 20 61 6e 73 77 65 72 20 3d 20 41 6e 73 77 answer = Answ
f170: 65 72 2e 6e 65 77 28 72 65 71 75 65 73 74 2e 61 er.new(request.a
f180: 72 74 69 66 61 63 74 73 2e 6d 61 70 20 7b 20 7c rtifacts.map { |
f190: 68 61 73 68 7c 20 41 72 74 69 66 61 63 74 2e 6e hash| Artifact.n
f1a0: 65 77 28 68 61 73 68 29 20 7d 2c 20 72 65 71 75 ew(hash) }, requ
f1b0: 65 73 74 2e 63 61 70 61 62 69 6c 69 74 69 65 73 est.capabilities
f1c0: 5f 6f 66 2e 74 72 79 20 7b 20 7c 6e 61 6d 65 7c _of.try { |name|
f1d0: 20 55 73 65 72 2e 6e 65 77 28 6e 61 6d 65 29 20 User.new(name)
f1e0: 7d 29 0a 20 20 20 20 65 6e 64 0a 20 20 20 20 73 }). end. s
f1f0: 6f 63 6b 65 74 2e 70 75 74 73 28 61 6e 73 77 65 ocket.puts(answe
f200: 72 2e 74 6f 5f 6a 73 6f 6e 29 0a 20 20 20 20 6f r.to_json). o
f210: 75 74 63 6f 6d 65 20 3d 20 22 6f 6b 22 0a 20 20 utcome = "ok".
f220: 72 65 73 63 75 65 20 65 78 20 3a 20 52 65 66 75 rescue ex : Refu
f230: 73 65 64 20 7c 20 4a 53 4f 4e 3a 3a 50 61 72 73 sed | JSON::Pars
f240: 65 45 78 63 65 70 74 69 6f 6e 0a 20 20 20 20 73 eException. s
f250: 6f 63 6b 65 74 2e 70 75 74 73 28 7b 72 65 66 75 ocket.puts({refu
f260: 73 65 64 3a 20 65 78 2e 69 73 5f 61 3f 28 52 65 sed: ex.is_a?(Re
f270: 66 75 73 65 64 29 20 3f 20 65 78 2e 6d 65 73 73 fused) ? ex.mess
f280: 61 67 65 20 3a 20 22 69 6e 76 61 6c 69 64 20 4a age : "invalid J
f290: 53 4f 4e 22 7d 2e 74 6f 5f 6a 73 6f 6e 29 0a 20 SON"}.to_json).
f2a0: 20 72 65 73 63 75 65 20 65 78 20 3a 20 55 6e 61 rescue ex : Una
f2b0: 76 61 69 6c 61 62 6c 65 0a 20 20 20 20 6f 75 74 vailable. out
f2c0: 63 6f 6d 65 20 3d 20 22 75 6e 61 76 61 69 6c 61 come = "unavaila
f2d0: 62 6c 65 22 0a 20 20 20 20 73 6f 63 6b 65 74 2e ble". socket.
f2e0: 70 75 74 73 28 7b 75 6e 61 76 61 69 6c 61 62 6c puts({unavailabl
f2f0: 65 3a 20 65 78 2e 6d 65 73 73 61 67 65 2c 20 72 e: ex.message, r
f300: 65 74 72 79 5f 61 66 74 65 72 3a 20 31 7d 2e 74 etry_after: 1}.t
f310: 6f 5f 6a 73 6f 6e 29 0a 20 20 72 65 73 63 75 65 o_json). rescue
f320: 20 65 78 20 3a 20 49 4f 3a 3a 45 72 72 6f 72 0a ex : IO::Error.
f330: 20 20 20 20 72 61 69 73 65 20 65 78 0a 20 20 72 raise ex. r
f340: 65 73 63 75 65 20 65 78 0a 20 20 20 20 23 20 41 escue ex. # A
f350: 6e 79 74 68 69 6e 67 20 75 6e 66 6f 72 65 73 65 nything unforese
f360: 65 6e 20 73 74 69 6c 6c 20 61 6e 73 77 65 72 73 en still answers
f370: 2c 20 73 6f 20 61 20 63 61 6c 6c 65 72 20 6e 65 , so a caller ne
f380: 76 65 72 20 77 61 69 74 73 20 6f 6e 20 61 20 73 ver waits on a s
f390: 69 6c 65 6e 74 20 63 6c 6f 73 65 2e 0a 20 20 20 ilent close..
f3a0: 20 6f 75 74 63 6f 6d 65 20 3d 20 22 75 6e 61 76 outcome = "unav
f3b0: 61 69 6c 61 62 6c 65 22 0a 20 20 20 20 73 6f 63 ailable". soc
f3c0: 6b 65 74 2e 70 75 74 73 28 7b 75 6e 61 76 61 69 ket.puts({unavai
f3d0: 6c 61 62 6c 65 3a 20 22 69 6e 74 65 72 6e 61 6c lable: "internal
f3e0: 20 65 72 72 6f 72 22 2c 20 72 65 74 72 79 5f 61 error", retry_a
f3f0: 66 74 65 72 3a 20 31 7d 2e 74 6f 5f 6a 73 6f 6e fter: 1}.to_json
f400: 29 0a 20 20 65 6e 73 75 72 65 0a 20 20 20 20 73 ). ensure. s
f410: 6f 63 6b 65 74 2e 63 6c 6f 73 65 0a 20 20 20 20 ocket.close.
f420: 53 54 44 45 52 52 2e 70 75 74 73 20 22 23 7b 54 STDERR.puts "#{T
f430: 69 6d 65 2e 75 74 63 2e 74 6f 5f 72 66 63 33 33 ime.utc.to_rfc33
f440: 33 39 7d 20 23 7b 72 65 70 6f 73 69 74 6f 72 79 39} #{repository
f450: 7d 20 23 7b 63 6f 75 6e 74 7d 20 23 7b 6f 75 74 } #{count} #{out
f460: 63 6f 6d 65 7d 20 23 7b 28 54 69 6d 65 2e 75 74 come} #{(Time.ut
f470: 63 20 2d 20 73 74 61 72 74 65 64 29 2e 74 6f 74 c - started).tot
f480: 61 6c 5f 6d 69 6c 6c 69 73 65 63 6f 6e 64 73 2e al_milliseconds.
f490: 74 6f 5f 69 36 34 7d 6d 73 22 0a 20 20 65 6e 64 to_i64}ms". end
f4a0: 0a 0a 20 20 23 20 50 61 73 73 69 6e 67 20 61 72 .. # Passing ar
f4b0: 67 75 6d 65 6e 74 73 20 74 68 72 6f 75 67 68 20 guments through
f4c0: 73 70 61 77 6e 20 63 6f 70 69 65 73 20 65 61 63 spawn copies eac
f4d0: 68 20 61 63 63 65 70 74 65 64 20 63 6f 6e 6e 65 h accepted conne
f4e0: 63 74 69 6f 6e 27 73 20 76 61 6c 75 65 73 2e 0a ction's values..
f4f0: 20 20 64 65 66 20 73 65 6c 66 2e 68 61 6e 64 6c def self.handl
f500: 65 28 73 6f 63 6b 65 74 20 3a 20 55 4e 49 58 53 e(socket : UNIXS
f510: 6f 63 6b 65 74 2c 20 72 65 70 6f 73 69 74 6f 72 ocket, repositor
f520: 69 65 73 20 3a 20 53 74 72 69 6e 67 2c 20 73 74 ies : String, st
f530: 61 72 74 65 64 20 3a 20 54 69 6d 65 2c 20 62 75 arted : Time, bu
f540: 73 79 20 3a 20 42 6f 6f 6c 2c 20 73 6c 6f 74 73 sy : Bool, slots
f550: 20 3a 20 43 68 61 6e 6e 65 6c 28 4e 69 6c 29 29 : Channel(Nil))
f560: 20 3a 20 4e 69 6c 0a 20 20 20 20 73 65 72 76 65 : Nil. serve
f570: 28 73 6f 63 6b 65 74 2c 20 72 65 70 6f 73 69 74 (socket, reposit
f580: 6f 72 69 65 73 2c 20 73 74 61 72 74 65 64 2c 20 ories, started,
f590: 62 75 73 79 29 0a 20 20 72 65 73 63 75 65 20 49 busy). rescue I
f5a0: 4f 3a 3a 45 72 72 6f 72 0a 20 20 20 20 23 20 54 O::Error. # T
f5b0: 68 65 20 63 61 6c 6c 65 72 20 6c 65 66 74 20 62 he caller left b
f5c0: 65 66 6f 72 65 20 69 74 73 20 61 6e 73 77 65 72 efore its answer
f5d0: 3b 20 73 65 72 76 65 27 73 20 65 6e 73 75 72 65 ; serve's ensure
f5e0: 20 6c 6f 67 67 65 64 20 74 68 65 20 63 6f 6e 6e logged the conn
f5f0: 65 63 74 69 6f 6e 2e 0a 20 20 65 6e 73 75 72 65 ection.. ensure
f600: 0a 20 20 20 20 73 6c 6f 74 73 2e 72 65 63 65 69 . slots.recei
f610: 76 65 20 75 6e 6c 65 73 73 20 62 75 73 79 0a 20 ve unless busy.
f620: 20 65 6e 64 0a 0a 20 20 64 65 66 20 73 65 6c 66 end.. def self
f630: 2e 72 75 6e 20 3a 20 4e 69 6c 0a 20 20 20 20 61 .run : Nil. a
f640: 62 6f 72 74 20 22 55 73 61 67 65 3a 20 72 65 63 bort "Usage: rec
f650: 65 69 70 74 73 20 53 4f 43 4b 45 54 20 52 45 50 eipts SOCKET REP
f660: 4f 53 49 54 4f 52 49 45 53 22 2c 20 32 20 75 6e OSITORIES", 2 un
f670: 6c 65 73 73 20 41 52 47 56 2e 73 69 7a 65 20 3d less ARGV.size =
f680: 3d 20 32 0a 20 20 20 20 73 6f 63 6b 65 74 5f 70 = 2. socket_p
f690: 61 74 68 2c 20 72 65 70 6f 73 69 74 6f 72 69 65 ath, repositorie
f6a0: 73 20 3d 20 41 52 47 56 0a 20 20 20 20 46 69 6c s = ARGV. Fil
f6b0: 65 2e 64 65 6c 65 74 65 28 73 6f 63 6b 65 74 5f e.delete(socket_
f6c0: 70 61 74 68 29 20 69 66 20 46 69 6c 65 2e 65 78 path) if File.ex
f6d0: 69 73 74 73 3f 28 73 6f 63 6b 65 74 5f 70 61 74 ists?(socket_pat
f6e0: 68 29 0a 20 20 20 20 73 65 72 76 65 72 20 3d 20 h). server =
f6f0: 55 4e 49 58 53 65 72 76 65 72 2e 6e 65 77 28 73 UNIXServer.new(s
f700: 6f 63 6b 65 74 5f 70 61 74 68 29 0a 20 20 20 20 ocket_path).
f710: 46 69 6c 65 2e 63 68 6d 6f 64 28 73 6f 63 6b 65 File.chmod(socke
f720: 74 5f 70 61 74 68 2c 20 30 6f 36 30 30 29 0a 20 t_path, 0o600).
f730: 20 20 20 73 6c 6f 74 73 20 3d 20 43 68 61 6e 6e slots = Chann
f740: 65 6c 28 4e 69 6c 29 2e 6e 65 77 28 38 29 0a 20 el(Nil).new(8).
f750: 20 20 20 77 68 69 6c 65 20 73 6f 63 6b 65 74 20 while socket
f760: 3d 20 73 65 72 76 65 72 2e 61 63 63 65 70 74 3f = server.accept?
f770: 0a 20 20 20 20 20 20 73 74 61 72 74 65 64 20 3d . started =
f780: 20 54 69 6d 65 2e 75 74 63 0a 20 20 20 20 20 20 Time.utc.
f790: 62 75 73 79 20 3d 20 73 65 6c 65 63 74 0a 20 20 busy = select.
f7a0: 20 20 20 20 77 68 65 6e 20 73 6c 6f 74 73 2e 73 when slots.s
f7b0: 65 6e 64 28 6e 69 6c 29 20 74 68 65 6e 20 66 61 end(nil) then fa
f7c0: 6c 73 65 0a 20 20 20 20 20 20 65 6c 73 65 0a 20 lse. else.
f7d0: 20 20 20 20 20 20 20 74 72 75 65 0a 20 20 20 20 true.
f7e0: 20 20 65 6e 64 0a 20 20 20 20 20 20 69 66 20 62 end. if b
f7f0: 75 73 79 0a 20 20 20 20 20 20 20 20 68 61 6e 64 usy. hand
f800: 6c 65 28 73 6f 63 6b 65 74 2c 20 72 65 70 6f 73 le(socket, repos
f810: 69 74 6f 72 69 65 73 2c 20 73 74 61 72 74 65 64 itories, started
f820: 2c 20 62 75 73 79 2c 20 73 6c 6f 74 73 29 0a 20 , busy, slots).
f830: 20 20 20 20 20 65 6c 73 65 0a 20 20 20 20 20 20 else.
f840: 20 20 73 70 61 77 6e 20 68 61 6e 64 6c 65 28 73 spawn handle(s
f850: 6f 63 6b 65 74 2c 20 72 65 70 6f 73 69 74 6f 72 ocket, repositor
f860: 69 65 73 2c 20 73 74 61 72 74 65 64 2c 20 62 75 ies, started, bu
f870: 73 79 2c 20 73 6c 6f 74 73 29 0a 20 20 20 20 20 sy, slots).
f880: 20 65 6e 64 0a 20 20 20 20 65 6e 64 0a 20 20 65 end. end. e
f890: 6e 64 0a 65 6e 64 0a 0a 52 65 63 65 69 70 74 73 nd.end..Receipts
f8a0: 2e 72 75 6e 0a 00 00 00 00 00 00 00 00 00 00 00 .run............
f8b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f8c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f8d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f8e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f8f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f920: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f930: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f940: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f950: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f960: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f970: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f990: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f9a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f9b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f9c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f9d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f9e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f9f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fa00: 73 74 61 67 65 41 2d 72 65 63 6f 72 64 2f 73 68 stageA-record/sh
fa10: 61 72 64 2e 79 6d 6c 2e 64 69 66 66 00 00 00 00 ard.yml.diff....
fa20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fa30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fa40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fa50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fa60: 00 00 00 00 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000
fa70: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
fa80: 30 30 30 31 33 35 32 00 31 35 32 37 30 34 37 36 0001352.15270476
fa90: 32 30 35 00 30 31 35 30 30 30 00 20 30 00 00 00 205.015000. 0...
faa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fab0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fac0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fad0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fae0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
faf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fb00: 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
fb10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fb20: 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
fb30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fb40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fb50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fb60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fb70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fb80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fb90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fba0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fbb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fbc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fbd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fbe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fbf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fc00: 49 6e 64 65 78 3a 20 73 68 61 72 64 2e 79 6d 6c Index: shard.yml
fc10: 0a 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d .===============
fc20: 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d ================
fc30: 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d ================
fc40: 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d ================
fc50: 3d 3d 3d 0a 2d 2d 2d 20 73 68 61 72 64 2e 79 6d ===.--- shard.ym
fc60: 6c 0a 2b 2b 2b 20 73 68 61 72 64 2e 79 6d 6c 0a l.+++ shard.yml.
fc70: 40 40 20 2d 31 30 2c 31 34 20 2b 31 30 2c 31 38 @@ -10,14 +10,18
fc80: 20 40 40 0a 20 20 20 73 71 6c 69 74 65 33 3a 0a @@. sqlite3:.
fc90: 20 20 20 20 20 67 69 74 68 75 62 3a 20 63 72 79 github: cry
fca0: 73 74 61 6c 2d 6c 61 6e 67 2f 63 72 79 73 74 61 stal-lang/crysta
fcb0: 6c 2d 73 71 6c 69 74 65 33 0a 20 20 20 20 20 76 l-sqlite3. v
fcc0: 65 72 73 69 6f 6e 3a 20 30 2e 32 33 2e 30 0a 20 ersion: 0.23.0.
fcd0: 0a 20 23 20 54 68 65 20 62 75 69 6c 64 20 73 74 . # The build st
fce0: 65 70 3a 20 60 73 68 61 72 64 73 20 62 75 69 6c ep: `shards buil
fcf0: 64 60 20 70 75 74 73 20 74 68 65 73 65 20 69 6e d` puts these in
fd00: 20 62 69 6e 2f 2e 20 53 69 6e 63 65 20 73 6c 69 bin/. Since sli
fd10: 63 65 20 31 20 4f 43 58 20 69 73 0a 2d 23 20 6f ce 1 OCX is.-# o
fd20: 6e 65 20 70 72 6f 67 72 61 6d 2c 20 6f 63 78 32 ne program, ocx2
fd30: 20 28 64 6f 63 73 2f 73 6c 69 63 65 73 2e 6d 64 (docs/slices.md
fd40: 29 2e 20 54 68 65 20 74 77 6f 20 62 75 69 6c 74 ). The two built
fd50: 20 66 72 6f 6d 20 73 63 72 69 70 74 73 2f 20 61 from scripts/ a
fd60: 72 65 20 74 68 65 20 6d 61 69 6e 74 61 69 6e 65 re the maintaine
fd70: 72 27 73 20 61 6e 64 20 72 75 6e 20 66 72 6f 6d r's and run from
fd80: 0a 2b 23 20 6f 6e 65 20 70 72 6f 67 72 61 6d 2c .+# one program,
fd90: 20 6f 63 78 32 20 28 64 6f 63 73 2f 73 6c 69 63 ocx2 (docs/slic
fda0: 65 73 2e 6d 64 29 2e 20 54 68 65 20 66 6f 75 72 es.md). The four
fdb0: 20 62 75 69 6c 74 20 66 72 6f 6d 20 73 63 72 69 built from scri
fdc0: 70 74 73 2f 20 61 72 65 20 74 68 65 20 6d 61 69 pts/ are the mai
fdd0: 6e 74 61 69 6e 65 72 27 73 20 61 6e 64 20 72 75 ntainer's and ru
fde0: 6e 20 66 72 6f 6d 0a 20 23 20 61 20 63 68 65 63 n from. # a chec
fdf0: 6b 6f 75 74 27 73 20 62 69 6e 2f 2e 0a 20 74 61 kout's bin/.. ta
fe00: 72 67 65 74 73 3a 0a 20 20 20 6f 63 78 32 3a 0a rgets:. ocx2:.
fe10: 20 20 20 20 20 6d 61 69 6e 3a 20 74 6f 6f 6c 73 main: tools
fe20: 2f 6f 63 78 32 2e 63 72 0a 20 20 20 73 74 61 72 /ocx2.cr. star
fe30: 74 2d 66 6f 73 73 69 6c 3a 0a 20 20 20 20 20 6d t-fossil:. m
fe40: 61 69 6e 3a 20 73 63 72 69 70 74 73 2f 73 74 61 ain: scripts/sta
fe50: 72 74 2d 66 6f 73 73 69 6c 2e 63 72 0a 20 20 20 rt-fossil.cr.
fe60: 73 79 6e 63 2d 66 6f 73 73 69 6c 3a 0a 20 20 20 sync-fossil:.
fe70: 20 20 6d 61 69 6e 3a 20 73 63 72 69 70 74 73 2f main: scripts/
fe80: 73 79 6e 63 2d 66 6f 73 73 69 6c 2e 63 72 0a 2b sync-fossil.cr.+
fe90: 20 20 73 74 61 72 74 2d 6f 63 78 3a 0a 2b 20 20 start-ocx:.+
fea0: 20 20 6d 61 69 6e 3a 20 73 63 72 69 70 74 73 2f main: scripts/
feb0: 73 74 61 72 74 2d 6f 63 78 2e 63 72 0a 2b 20 20 start-ocx.cr.+
fec0: 72 65 63 65 69 70 74 73 3a 0a 2b 20 20 20 20 6d receipts:.+ m
fed0: 61 69 6e 3a 20 73 63 72 69 70 74 73 2f 72 65 63 ain: scripts/rec
fee0: 65 69 70 74 73 2e 63 72 0a 0a 00 00 00 00 00 00 eipts.cr........
fef0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ff10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ff20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ff30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ff40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ff50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ff60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ff70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ff90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ffa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ffb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ffc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ffd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
ffe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
fff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10000 73 74 61 67 65 41 2d 72 65 63 6f 72 64 2f 52 45 stageA-record/RE
10010 41 44 4d 45 2e 74 78 74 00 00 00 00 00 00 00 00 ADME.txt........
10020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10060 00 00 00 00 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000
10070 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
10080 30 30 30 30 36 36 33 00 31 35 32 37 30 34 37 36 0000663.15270476
10090 32 30 35 00 30 31 33 37 34 37 00 20 30 00 00 00 205.013747. 0...
100a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
100b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
100c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
100d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
100e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
100f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10100 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
10110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10120 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
10130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
101a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
101b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
101c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
101d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
101e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
101f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10200 53 74 61 67 65 20 41 20 6f 6e 20 61 20 73 63 72 Stage A on a scr
10210 61 74 63 68 20 64 65 70 6c 6f 79 6d 65 6e 74 2c atch deployment,
10220 20 32 30 32 36 2d 31 30 2d 32 38 20 7e 32 32 3a 2026-10-28 ~22:
10230 34 35 20 55 54 43 2c 20 73 74 6f 63 6b 20 46 6f 45 UTC, stock Fo
10240 73 73 69 6c 20 32 2e 32 37 2e 0a 72 65 63 6f 72 ssil 2.27..recor
10250 64 2e 74 78 74 3a 20 74 68 65 20 77 68 6f 6c 65 d.txt: the whole
10260 20 72 75 6e 20 6f 66 20 73 74 61 67 65 41 2d 64 run of stageA-d
10270 65 6d 6f 2e 73 68 20 28 69 74 73 20 68 61 72 6e emo.sh (its harn
10280 65 73 73 29 2c 20 70 72 6f 62 65 2e 63 72 3a 20 ess), probe.cr:
10290 74 68 65 20 70 72 6f 67 72 61 6d 20 70 75 74 20 the program put
102a0 69 6e 20 70 6c 61 63 65 20 6f 66 20 72 65 63 65 in place of rece
102b0 69 70 74 73 20 74 6f 20 74 72 79 20 77 72 69 74 ipts to try writ
102c0 65 73 20 61 6e 64 20 74 68 65 20 6e 65 74 77 6f es and the netwo
102d0 72 6b 2e 0a 73 74 61 72 74 2d 6f 63 78 2e 63 72 rk..start-ocx.cr
102e0 2c 20 72 65 63 65 69 70 74 73 2e 63 72 2c 20 73 , receipts.cr, s
102f0 68 61 72 64 2e 79 6d 6c 2e 64 69 66 66 3a 20 74 hard.yml.diff: t
10300 68 65 20 74 77 6f 20 73 63 72 69 70 74 73 2f 20 he two scripts/
10310 70 72 6f 67 72 61 6d 73 20 61 6e 64 20 74 68 65 programs and the
10320 69 72 20 62 75 69 6c 64 20 74 61 72 67 65 74 73 ir build targets
10330 2c 20 4e 4f 54 20 63 6f 6d 6d 69 74 74 65 64 2c , NOT committed,
10340 20 66 6f 72 20 74 68 65 20 6d 61 69 6e 74 61 69 for the maintai
10350 6e 65 72 27 73 20 73 74 72 69 63 74 20 72 65 76 ner's strict rev
10360 69 65 77 20 28 64 65 63 69 73 69 6f 6e 20 32 32 iew (decision 22
10370 29 2e 0a 73 74 61 67 65 41 2d 70 6c 61 6e 2e 6d )..stageA-plan.m
10380 64 2c 20 73 74 61 67 65 41 2d 6f 63 78 2d 70 6c d, stageA-ocx-pl
10390 61 6e 2e 6d 64 3a 20 74 68 65 20 70 6c 61 6e 73 an.md: the plans
103a0 20 43 6f 64 65 78 20 62 75 69 6c 74 20 66 72 6f Codex built fro
103b0 6d 2e 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 m...............
103c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
103d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
103e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
103f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10400 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10410 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10420 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10430 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10440 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10450 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10460 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10470 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10480 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10490 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
104a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
104b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
104c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
104d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
104e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
104f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10500 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10510 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10520 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10530 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10540 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10550 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10560 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10570 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10580 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10590 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
105a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
105b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
105c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
105d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
105e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
105f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10600 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10610 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10620 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10630 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10640 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10650 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10660 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10670 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10680 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10690 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
106a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
106b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
106c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
106d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
106e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
106f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10700 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10710 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10720 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10730 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10740 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10750 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10760 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10770 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10780 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10790 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
107a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
107b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
107c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
107d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
107e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
107f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................