Attachment "scripts-for-review-3.tar" to
tech note [bae6999eb9]
added by
opus-ocx2
2026-10-29 15:43:07.
0000: 73 63 72 69 70 74 73 2d 66 6f 72 2d 72 65 76 69 scripts-for-revi
0010: 65 77 2d 33 2f 00 00 00 00 00 00 00 00 00 00 00 ew-3/...........
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 36 36 34 0000000.15270664
0090: 36 31 33 00 30 31 33 35 30 30 00 20 35 00 00 00 613.013500. 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 63 72 69 70 74 73 2d 66 6f 72 2d 72 65 76 69 scripts-for-revi
0210: 65 77 2d 33 2f 72 65 63 65 69 70 74 73 2e 63 72 ew-3/receipts.cr
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 32 33 30 30 34 00 31 35 32 37 30 36 36 34 0023004.15270664
0290: 36 31 33 00 30 31 35 36 34 33 00 20 30 00 00 00 613.015643. 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: 23 20 41 67 65 6e 74 73 3a 20 64 6f 20 6e 6f 74 # Agents: do not
0410: 20 63 68 61 6e 67 65 20 74 68 69 73 20 66 69 6c change this fil
0420: 65 20 6f 6e 20 61 6e 79 20 62 72 61 6e 63 68 20 e on any branch
0430: 77 69 74 68 6f 75 74 20 74 68 65 20 6d 61 69 6e without the main
0440: 74 61 69 6e 65 72 27 73 20 65 78 70 6c 69 63 69 tainer's explici
0450: 74 20 61 70 70 72 6f 76 61 6c 20 6f 6e 20 74 68 t approval on th
0460: 65 20 72 65 63 6f 72 64 2e 0a 23 20 54 68 65 20 e record..# The
0470: 72 65 63 65 69 70 74 20 73 65 72 76 69 63 65 3a receipt service:
0480: 20 73 61 79 73 20 77 68 6f 20 46 6f 73 73 69 6c says who Fossil
0490: 20 72 65 63 65 69 76 65 64 20 65 61 63 68 20 61 received each a
04a0: 72 74 69 66 61 63 74 20 66 72 6f 6d 2c 20 72 65 rtifact from, re
04b0: 61 64 69 6e 67 20 74 68 65 20 73 65 72 76 65 64 ading the served
04c0: 20 72 65 70 6f 73 69 74 6f 72 69 65 73 20 72 65 repositories re
04d0: 61 64 2d 6f 6e 6c 79 2e 0a 23 20 60 73 74 61 72 ad-only..# `star
04e0: 74 2d 6f 63 78 20 72 65 63 65 69 70 74 73 60 20 t-ocx receipts`
04f0: 72 75 6e 73 20 69 74 20 69 6e 20 61 20 73 61 6e runs it in a san
0500: 64 62 6f 78 20 68 6f 6c 64 69 6e 67 20 6f 6e 6c dbox holding onl
0510: 79 20 74 68 65 20 74 77 6f 20 70 61 74 68 73 20 y the two paths
0520: 62 65 6c 6f 77 2c 20 73 6f 20 69 74 20 72 65 61 below, so it rea
0530: 64 73 20 6e 6f 20 73 65 74 74 69 6e 67 73 20 66 ds no settings f
0540: 69 6c 65 2e 0a 23 20 45 61 63 68 20 63 6f 6e 6e ile..# Each conn
0550: 65 63 74 69 6f 6e 3a 20 74 68 65 20 6c 61 75 6e ection: the laun
0560: 63 68 65 72 27 73 20 69 64 65 6e 74 69 74 79 20 cher's identity
0570: 6c 69 6e 65 2c 20 74 68 65 6e 20 74 68 65 20 63 line, then the c
0580: 61 6c 6c 65 72 27 73 20 72 65 71 75 65 73 74 20 aller's request
0590: 6c 69 6e 65 3b 20 6f 6e 65 20 61 6e 73 77 65 72 line; one answer
05a0: 20 6c 69 6e 65 20 62 61 63 6b 2e 0a 53 4f 43 4b line back..SOCK
05b0: 45 54 20 20 20 20 20 20 20 3d 20 22 2f 72 75 6e ET = "/run
05c0: 2f 6f 63 78 2f 72 65 63 65 69 70 74 73 2e 73 6f /ocx/receipts.so
05d0: 63 6b 22 20 23 20 77 68 65 72 65 20 74 68 65 20 ck" # where the
05e0: 6c 61 75 6e 63 68 65 72 20 63 6f 6e 6e 65 63 74 launcher connect
05f0: 73 0a 52 45 50 4f 53 49 54 4f 52 49 45 53 20 3d s.REPOSITORIES =
0600: 20 22 2f 72 65 70 6f 73 69 74 6f 72 69 65 73 22 "/repositories"
0610: 20 20 20 20 20 20 20 20 20 20 23 20 74 68 65 20 # the
0620: 73 65 72 76 65 64 20 72 65 70 6f 73 69 74 6f 72 served repositor
0630: 69 65 73 2c 20 72 65 61 64 2d 6f 6e 6c 79 0a 52 ies, read-only.R
0640: 45 41 44 5f 57 49 54 48 49 4e 20 20 3d 20 32 2e EAD_WITHIN = 2.
0650: 73 65 63 6f 6e 64 73 20 20 20 20 20 20 20 20 20 seconds
0660: 20 20 20 20 20 20 20 23 20 62 6f 74 68 20 72 65 # both re
0670: 71 75 65 73 74 20 6c 69 6e 65 73 20 6d 75 73 74 quest lines must
0680: 20 61 72 72 69 76 65 20 62 79 20 74 68 65 6e 0a arrive by then.
0690: 4c 4f 43 4b 5f 57 41 49 54 20 20 20 20 3d 20 32 LOCK_WAIT = 2
06a0: 2e 73 65 63 6f 6e 64 73 20 20 20 20 20 20 20 20 .seconds
06b0: 20 20 20 20 20 20 20 20 23 20 74 68 65 20 6c 6f # the lo
06c0: 6e 67 65 73 74 20 77 61 69 74 20 77 68 69 6c 65 ngest wait while
06d0: 20 46 6f 73 73 69 6c 20 68 6f 6c 64 73 20 61 20 Fossil holds a
06e0: 72 65 70 6f 73 69 74 6f 72 79 20 6c 6f 63 6b 65 repository locke
06f0: 64 0a 0a 72 65 71 75 69 72 65 20 22 6a 73 6f 6e d..require "json
0700: 22 0a 72 65 71 75 69 72 65 20 22 73 6f 63 6b 65 ".require "socke
0710: 74 22 0a 72 65 71 75 69 72 65 20 22 75 72 69 22 t".require "uri"
0720: 0a 0a 23 20 54 68 65 20 70 61 72 74 73 20 6f 66 ..# The parts of
0730: 20 53 51 4c 69 74 65 27 73 20 43 20 69 6e 74 65 SQLite's C inte
0740: 72 66 61 63 65 20 75 73 65 64 20 68 65 72 65 2e rface used here.
0750: 0a 40 5b 4c 69 6e 6b 28 22 73 71 6c 69 74 65 33 .@[Link("sqlite3
0760: 22 29 5d 0a 6c 69 62 20 4c 69 62 53 51 4c 69 74 ")].lib LibSQLit
0770: 65 33 0a 20 20 66 75 6e 20 6f 70 65 6e 5f 76 32 e3. fun open_v2
0780: 20 3d 20 73 71 6c 69 74 65 33 5f 6f 70 65 6e 5f = sqlite3_open_
0790: 76 32 28 70 61 74 68 20 3a 20 55 49 6e 74 38 2a v2(path : UInt8*
07a0: 2c 20 64 62 20 3a 20 56 6f 69 64 2a 2a 2c 20 66 , db : Void**, f
07b0: 6c 61 67 73 20 3a 20 49 6e 74 33 32 2c 20 76 66 lags : Int32, vf
07c0: 73 20 3a 20 55 49 6e 74 38 2a 29 20 3a 20 49 6e s : UInt8*) : In
07d0: 74 33 32 0a 20 20 66 75 6e 20 63 6c 6f 73 65 5f t32. fun close_
07e0: 76 32 20 3d 20 73 71 6c 69 74 65 33 5f 63 6c 6f v2 = sqlite3_clo
07f0: 73 65 5f 76 32 28 64 62 20 3a 20 56 6f 69 64 2a se_v2(db : Void*
0800: 29 20 3a 20 49 6e 74 33 32 0a 20 20 66 75 6e 20 ) : Int32. fun
0810: 62 75 73 79 5f 74 69 6d 65 6f 75 74 20 3d 20 73 busy_timeout = s
0820: 71 6c 69 74 65 33 5f 62 75 73 79 5f 74 69 6d 65 qlite3_busy_time
0830: 6f 75 74 28 64 62 20 3a 20 56 6f 69 64 2a 2c 20 out(db : Void*,
0840: 6d 69 6c 6c 69 73 65 63 6f 6e 64 73 20 3a 20 49 milliseconds : I
0850: 6e 74 33 32 29 20 3a 20 49 6e 74 33 32 0a 20 20 nt32) : Int32.
0860: 66 75 6e 20 70 72 65 70 61 72 65 5f 76 32 20 3d fun prepare_v2 =
0870: 20 73 71 6c 69 74 65 33 5f 70 72 65 70 61 72 65 sqlite3_prepare
0880: 5f 76 32 28 64 62 20 3a 20 56 6f 69 64 2a 2c 20 _v2(db : Void*,
0890: 73 71 6c 20 3a 20 55 49 6e 74 38 2a 2c 20 73 69 sql : UInt8*, si
08a0: 7a 65 20 3a 20 49 6e 74 33 32 2c 20 73 74 61 74 ze : Int32, stat
08b0: 65 6d 65 6e 74 20 3a 20 56 6f 69 64 2a 2a 2c 20 ement : Void**,
08c0: 74 61 69 6c 20 3a 20 55 49 6e 74 38 2a 2a 29 20 tail : UInt8**)
08d0: 3a 20 49 6e 74 33 32 0a 20 20 66 75 6e 20 62 69 : Int32. fun bi
08e0: 6e 64 5f 74 65 78 74 20 3d 20 73 71 6c 69 74 65 nd_text = sqlite
08f0: 33 5f 62 69 6e 64 5f 74 65 78 74 28 73 74 61 74 3_bind_text(stat
0900: 65 6d 65 6e 74 20 3a 20 56 6f 69 64 2a 2c 20 69 ement : Void*, i
0910: 6e 64 65 78 20 3a 20 49 6e 74 33 32 2c 20 74 65 ndex : Int32, te
0920: 78 74 20 3a 20 55 49 6e 74 38 2a 2c 20 73 69 7a xt : UInt8*, siz
0930: 65 20 3a 20 49 6e 74 33 32 2c 20 64 65 73 74 72 e : Int32, destr
0940: 75 63 74 6f 72 20 3a 20 56 6f 69 64 2a 29 20 3a uctor : Void*) :
0950: 20 49 6e 74 33 32 0a 20 20 66 75 6e 20 73 74 65 Int32. fun ste
0960: 70 20 3d 20 73 71 6c 69 74 65 33 5f 73 74 65 70 p = sqlite3_step
0970: 28 73 74 61 74 65 6d 65 6e 74 20 3a 20 56 6f 69 (statement : Voi
0980: 64 2a 29 20 3a 20 49 6e 74 33 32 0a 20 20 66 75 d*) : Int32. fu
0990: 6e 20 63 6f 6c 75 6d 6e 5f 63 6f 75 6e 74 20 3d n column_count =
09a0: 20 73 71 6c 69 74 65 33 5f 63 6f 6c 75 6d 6e 5f sqlite3_column_
09b0: 63 6f 75 6e 74 28 73 74 61 74 65 6d 65 6e 74 20 count(statement
09c0: 3a 20 56 6f 69 64 2a 29 20 3a 20 49 6e 74 33 32 : Void*) : Int32
09d0: 0a 20 20 66 75 6e 20 63 6f 6c 75 6d 6e 5f 74 65 . fun column_te
09e0: 78 74 20 3d 20 73 71 6c 69 74 65 33 5f 63 6f 6c xt = sqlite3_col
09f0: 75 6d 6e 5f 74 65 78 74 28 73 74 61 74 65 6d 65 umn_text(stateme
0a00: 6e 74 20 3a 20 56 6f 69 64 2a 2c 20 63 6f 6c 75 nt : Void*, colu
0a10: 6d 6e 20 3a 20 49 6e 74 33 32 29 20 3a 20 55 49 mn : Int32) : UI
0a20: 6e 74 38 2a 0a 20 20 66 75 6e 20 66 69 6e 61 6c nt8*. fun final
0a30: 69 7a 65 20 3d 20 73 71 6c 69 74 65 33 5f 66 69 ize = sqlite3_fi
0a40: 6e 61 6c 69 7a 65 28 73 74 61 74 65 6d 65 6e 74 nalize(statement
0a50: 20 3a 20 56 6f 69 64 2a 29 20 3a 20 49 6e 74 33 : Void*) : Int3
0a60: 32 0a 20 20 66 75 6e 20 65 72 72 6d 73 67 20 3d 2. fun errmsg =
0a70: 20 73 71 6c 69 74 65 33 5f 65 72 72 6d 73 67 28 sqlite3_errmsg(
0a80: 64 62 20 3a 20 56 6f 69 64 2a 29 20 3a 20 55 49 db : Void*) : UI
0a90: 6e 74 38 2a 0a 65 6e 64 0a 0a 23 20 54 68 65 20 nt8*.end..# The
0aa0: 6f 6e 6c 79 20 71 75 65 72 69 65 73 2e 20 41 20 only queries. A
0ab0: 63 61 6c 6c 65 72 27 73 20 76 61 6c 75 65 20 69 caller's value i
0ac0: 73 20 62 6f 75 6e 64 20 74 6f 20 3f 31 2c 20 6e s bound to ?1, n
0ad0: 65 76 65 72 20 77 72 69 74 74 65 6e 20 69 6e 74 ever written int
0ae0: 6f 20 74 68 65 20 53 51 4c 2e 0a 41 52 54 49 46 o the SQL..ARTIF
0af0: 41 43 54 20 3d 20 22 53 45 4c 45 43 54 20 62 2e ACT = "SELECT b.
0b00: 72 69 64 2c 20 62 2e 72 63 76 69 64 2c 20 45 58 rid, b.rcvid, EX
0b10: 49 53 54 53 28 53 45 4c 45 43 54 20 31 20 46 52 ISTS(SELECT 1 FR
0b20: 4f 4d 20 70 72 69 76 61 74 65 20 70 20 57 48 45 OM private p WHE
0b30: 52 45 20 70 2e 72 69 64 3d 62 2e 72 69 64 29 2c RE p.rid=b.rid),
0b40: 20 75 2e 6c 6f 67 69 6e 2c 20 75 2e 63 61 70 20 u.login, u.cap
0b50: 46 52 4f 4d 20 62 6c 6f 62 20 62 20 22 20 5c 0a FROM blob b " \.
0b60: 20 20 20 20 20 20 20 20 20 20 20 22 4c 45 46 54 "LEFT
0b70: 20 4a 4f 49 4e 20 72 63 76 66 72 6f 6d 20 72 20 JOIN rcvfrom r
0b80: 4f 4e 20 72 2e 72 63 76 69 64 3d 62 2e 72 63 76 ON r.rcvid=b.rcv
0b90: 69 64 20 4c 45 46 54 20 4a 4f 49 4e 20 75 73 65 id LEFT JOIN use
0ba0: 72 20 75 20 4f 4e 20 75 2e 75 69 64 3d 72 2e 75 r u ON u.uid=r.u
0bb0: 69 64 20 57 48 45 52 45 20 62 2e 75 75 69 64 3d id WHERE b.uuid=
0bc0: 3f 31 20 41 4e 44 20 62 2e 73 69 7a 65 3e 3d 30 ?1 AND b.size>=0
0bd0: 22 0a 55 53 45 52 20 20 20 20 20 3d 20 22 53 45 ".USER = "SE
0be0: 4c 45 43 54 20 63 61 70 20 46 52 4f 4d 20 75 73 LECT cap FROM us
0bf0: 65 72 20 57 48 45 52 45 20 6c 6f 67 69 6e 3d 3f er WHERE login=?
0c00: 31 22 0a 44 45 46 41 55 4c 54 53 20 3d 20 22 53 1".DEFAULTS = "S
0c10: 45 4c 45 43 54 20 6c 6f 67 69 6e 2c 20 63 61 70 ELECT login, cap
0c20: 20 46 52 4f 4d 20 75 73 65 72 20 57 48 45 52 45 FROM user WHERE
0c30: 20 6c 6f 67 69 6e 20 49 4e 20 28 27 6e 6f 62 6f login IN ('nobo
0c40: 64 79 27 2c 27 61 6e 6f 6e 79 6d 6f 75 73 27 2c dy','anonymous',
0c50: 27 72 65 61 64 65 72 27 2c 27 64 65 76 65 6c 6f 'reader','develo
0c60: 70 65 72 27 29 22 0a 53 45 54 54 49 4e 47 20 20 per')".SETTING
0c70: 3d 20 22 53 45 4c 45 43 54 20 76 61 6c 75 65 20 = "SELECT value
0c80: 46 52 4f 4d 20 63 6f 6e 66 69 67 20 57 48 45 52 FROM config WHER
0c90: 45 20 6e 61 6d 65 3d 3f 31 22 0a 0a 23 20 57 68 E name=?1"..# Wh
0ca0: 61 74 20 61 72 72 69 76 65 73 2c 20 61 6e 64 20 at arrives, and
0cb0: 77 68 61 74 20 69 73 20 61 6e 73 77 65 72 65 64 what is answered
0cc0: 2e 0a 73 74 72 75 63 74 20 49 64 65 6e 74 69 74 ..struct Identit
0cd0: 79 20 23 20 66 72 6f 6d 20 74 68 65 20 6c 61 75 y # from the lau
0ce0: 6e 63 68 65 72 2c 20 61 73 20 46 6f 73 73 69 6c ncher, as Fossil
0cf0: 20 67 61 76 65 20 69 74 0a 20 20 69 6e 63 6c 75 gave it. inclu
0d00: 64 65 20 4a 53 4f 4e 3a 3a 53 65 72 69 61 6c 69 de JSON::Seriali
0d10: 7a 61 62 6c 65 0a 20 20 67 65 74 74 65 72 20 75 zable. getter u
0d20: 73 65 72 20 3a 20 53 74 72 69 6e 67 3f 0a 20 20 ser : String?.
0d30: 67 65 74 74 65 72 20 63 61 70 61 62 69 6c 69 74 getter capabilit
0d40: 69 65 73 20 3a 20 53 74 72 69 6e 67 0a 20 20 67 ies : String. g
0d50: 65 74 74 65 72 20 72 65 70 6f 73 69 74 6f 72 79 etter repository
0d60: 20 3a 20 53 74 72 69 6e 67 0a 65 6e 64 0a 0a 73 : String.end..s
0d70: 74 72 75 63 74 20 52 65 71 75 65 73 74 20 23 20 truct Request #
0d80: 66 72 6f 6d 20 74 68 65 20 63 61 6c 6c 65 72 3b from the caller;
0d90: 20 61 6e 79 20 6f 74 68 65 72 20 6b 65 79 20 69 any other key i
0da0: 73 20 72 65 66 75 73 65 64 0a 20 20 69 6e 63 6c s refused. incl
0db0: 75 64 65 20 4a 53 4f 4e 3a 3a 53 65 72 69 61 6c ude JSON::Serial
0dc0: 69 7a 61 62 6c 65 0a 20 20 69 6e 63 6c 75 64 65 izable. include
0dd0: 20 4a 53 4f 4e 3a 3a 53 65 72 69 61 6c 69 7a 61 JSON::Serializa
0de0: 62 6c 65 3a 3a 53 74 72 69 63 74 0a 20 20 67 65 ble::Strict. ge
0df0: 74 74 65 72 20 6f 63 78 5f 72 65 63 65 69 70 74 tter ocx_receipt
0e00: 20 3a 20 49 6e 74 33 32 0a 20 20 67 65 74 74 65 : Int32. gette
0e10: 72 20 61 72 74 69 66 61 63 74 73 20 3d 20 5b 5d r artifacts = []
0e20: 20 6f 66 20 53 74 72 69 6e 67 0a 20 20 67 65 74 of String. get
0e30: 74 65 72 20 63 61 70 61 62 69 6c 69 74 69 65 73 ter capabilities
0e40: 5f 6f 66 20 3a 20 53 74 72 69 6e 67 3f 0a 65 6e _of : String?.en
0e50: 64 0a 0a 63 6c 61 73 73 20 41 72 74 69 66 61 63 d..class Artifac
0e60: 74 0a 20 20 69 6e 63 6c 75 64 65 20 4a 53 4f 4e t. include JSON
0e70: 3a 3a 53 65 72 69 61 6c 69 7a 61 62 6c 65 0a 20 ::Serializable.
0e80: 20 70 72 6f 70 65 72 74 79 20 61 72 74 69 66 61 property artifa
0e90: 63 74 20 3a 20 53 74 72 69 6e 67 2c 20 72 65 63 ct : String, rec
0ea0: 65 69 76 65 64 20 3d 20 66 61 6c 73 65 2c 20 73 eived = false, s
0eb0: 65 6e 64 65 72 20 3a 20 53 74 72 69 6e 67 3f 20 ender : String?
0ec0: 3d 20 6e 69 6c 2c 20 63 61 70 61 62 69 6c 69 74 = nil, capabilit
0ed0: 69 65 73 20 3a 20 53 74 72 69 6e 67 3f 20 3d 20 ies : String? =
0ee0: 6e 69 6c 0a 20 20 70 72 6f 70 65 72 74 79 20 72 nil. property r
0ef0: 65 63 65 69 70 74 20 3a 20 49 6e 74 36 34 3f 20 eceipt : Int64?
0f00: 3d 20 6e 69 6c 2c 20 72 69 64 20 3a 20 49 6e 74 = nil, rid : Int
0f10: 36 34 3f 20 3d 20 6e 69 6c 0a 0a 20 20 64 65 66 64? = nil.. def
0f20: 20 69 6e 69 74 69 61 6c 69 7a 65 28 40 61 72 74 initialize(@art
0f30: 69 66 61 63 74 29 3b 20 65 6e 64 0a 65 6e 64 0a ifact); end.end.
0f40: 0a 63 6c 61 73 73 20 55 73 65 72 0a 20 20 69 6e .class User. in
0f50: 63 6c 75 64 65 20 4a 53 4f 4e 3a 3a 53 65 72 69 clude JSON::Seri
0f60: 61 6c 69 7a 61 62 6c 65 0a 20 20 70 72 6f 70 65 alizable. prope
0f70: 72 74 79 20 75 73 65 72 20 3a 20 53 74 72 69 6e rty user : Strin
0f80: 67 0a 20 20 40 5b 4a 53 4f 4e 3a 3a 46 69 65 6c g. @[JSON::Fiel
0f90: 64 28 65 6d 69 74 5f 6e 75 6c 6c 3a 20 74 72 75 d(emit_null: tru
0fa0: 65 29 5d 0a 20 20 70 72 6f 70 65 72 74 79 20 63 e)]. property c
0fb0: 61 70 61 62 69 6c 69 74 69 65 73 20 3a 20 53 74 apabilities : St
0fc0: 72 69 6e 67 3f 20 3d 20 6e 69 6c 0a 20 20 70 72 ring? = nil. pr
0fd0: 6f 70 65 72 74 79 20 77 69 6b 69 5f 6d 6f 64 65 operty wiki_mode
0fe0: 72 61 74 65 64 20 3a 20 42 6f 6f 6c 3f 20 3d 20 rated : Bool? =
0ff0: 6e 69 6c 2c 20 74 69 63 6b 65 74 5f 6d 6f 64 65 nil, ticket_mode
1000: 72 61 74 65 64 20 3a 20 42 6f 6f 6c 3f 20 3d 20 rated : Bool? =
1010: 6e 69 6c 0a 0a 20 20 64 65 66 20 69 6e 69 74 69 nil.. def initi
1020: 61 6c 69 7a 65 28 40 75 73 65 72 29 3b 20 65 6e alize(@user); en
1030: 64 0a 65 6e 64 0a 0a 72 65 63 6f 72 64 20 41 6e d.end..record An
1040: 73 77 65 72 2c 20 61 72 74 69 66 61 63 74 73 20 swer, artifacts
1050: 3a 20 41 72 72 61 79 28 41 72 74 69 66 61 63 74 : Array(Artifact
1060: 29 2c 20 75 73 65 72 20 3a 20 55 73 65 72 3f 20 ), user : User?
1070: 7b 20 69 6e 63 6c 75 64 65 20 4a 53 4f 4e 3a 3a { include JSON::
1080: 53 65 72 69 61 6c 69 7a 61 62 6c 65 20 7d 0a 0a Serializable }..
1090: 63 6c 61 73 73 20 52 65 66 75 73 65 64 20 3c 20 class Refused <
10a0: 45 78 63 65 70 74 69 6f 6e 3b 20 65 6e 64 20 23 Exception; end #
10b0: 20 61 20 62 61 64 20 72 65 71 75 65 73 74 0a 0a a bad request..
10c0: 63 6c 61 73 73 20 4c 6f 63 6b 65 64 20 3c 20 45 class Locked < E
10d0: 78 63 65 70 74 69 6f 6e 3b 20 65 6e 64 20 23 20 xception; end #
10e0: 46 6f 73 73 69 6c 20 69 73 20 77 72 69 74 69 6e Fossil is writin
10f0: 67 3a 20 77 61 69 74 20 61 6e 64 20 74 72 79 20 g: wait and try
1100: 61 67 61 69 6e 0a 0a 23 20 41 20 75 73 65 72 27 again..# A user'
1110: 73 20 63 61 70 61 62 69 6c 69 74 69 65 73 20 61 s capabilities a
1120: 73 20 46 6f 73 73 69 6c 20 65 78 70 61 6e 64 73 s Fossil expands
1130: 20 74 68 65 6d 3a 20 74 68 65 69 72 20 6f 77 6e them: their own
1140: 2c 20 61 6e 6f 6e 79 6d 6f 75 73 27 73 20 61 6e , anonymous's an
1150: 64 20 6e 6f 62 6f 64 79 27 73 2c 20 74 68 65 6e d nobody's, then
1160: 20 61 64 6d 69 6e 27 73 2c 20 64 65 76 65 6c 6f admin's, develo
1170: 70 65 72 27 73 20 61 6e 64 20 72 65 61 64 65 72 per's and reader
1180: 27 73 2e 0a 64 65 66 20 65 78 70 61 6e 64 65 64 's..def expanded
1190: 28 63 61 70 20 3a 20 53 74 72 69 6e 67 2c 20 73 (cap : String, s
11a0: 70 65 63 69 61 6c 20 3a 20 48 61 73 68 28 53 74 pecial : Hash(St
11b0: 72 69 6e 67 2c 20 53 74 72 69 6e 67 29 29 20 3a ring, String)) :
11c0: 20 53 74 72 69 6e 67 0a 20 20 63 61 70 20 2b 3d String. cap +=
11d0: 20 73 70 65 63 69 61 6c 5b 22 61 6e 6f 6e 79 6d special["anonym
11e0: 6f 75 73 22 5d 3f 2e 74 6f 5f 73 20 2b 20 73 70 ous"]?.to_s + sp
11f0: 65 63 69 61 6c 5b 22 6e 6f 62 6f 64 79 22 5d 3f ecial["nobody"]?
1200: 2e 74 6f 5f 73 0a 20 20 63 61 70 20 2b 3d 20 22 .to_s. cap += "
1210: 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 bcdefghijklmnopq
1220: 72 74 77 7a 32 33 34 35 36 37 41 44 22 20 69 66 rtwz234567AD" if
1230: 20 63 61 70 2e 69 6e 63 6c 75 64 65 73 3f 28 27 cap.includes?('
1240: 61 27 29 20 7c 7c 20 63 61 70 2e 69 6e 63 6c 75 a') || cap.inclu
1250: 64 65 73 3f 28 27 73 27 29 0a 20 20 63 61 70 20 des?('s'). cap
1260: 2b 3d 20 73 70 65 63 69 61 6c 5b 22 64 65 76 65 += special["deve
1270: 6c 6f 70 65 72 22 5d 3f 2e 74 6f 5f 73 20 69 66 loper"]?.to_s if
1280: 20 63 61 70 2e 69 6e 63 6c 75 64 65 73 3f 28 27 cap.includes?('
1290: 76 27 29 0a 20 20 63 61 70 20 2b 3d 20 73 70 65 v'). cap += spe
12a0: 63 69 61 6c 5b 22 72 65 61 64 65 72 22 5d 3f 2e cial["reader"]?.
12b0: 74 6f 5f 73 20 69 66 20 63 61 70 2e 69 6e 63 6c to_s if cap.incl
12c0: 75 64 65 73 3f 28 27 75 27 29 0a 20 20 63 61 70 udes?('u'). cap
12d0: 20 2b 3d 20 73 70 65 63 69 61 6c 5b 22 64 65 76 += special["dev
12e0: 65 6c 6f 70 65 72 22 5d 3f 2e 74 6f 5f 73 20 69 eloper"]?.to_s i
12f0: 66 20 63 61 70 2e 69 6e 63 6c 75 64 65 73 3f 28 f cap.includes?(
1300: 27 76 27 29 0a 20 20 28 22 61 22 2e 2e 22 7a 22 'v'). ("a".."z"
1310: 29 2e 74 6f 5f 61 2e 63 6f 6e 63 61 74 28 28 22 ).to_a.concat(("
1320: 30 22 2e 2e 22 39 22 29 2e 74 6f 5f 61 29 2e 63 0".."9").to_a).c
1330: 6f 6e 63 61 74 28 28 22 41 22 2e 2e 22 5a 22 29 oncat(("A".."Z")
1340: 2e 74 6f 5f 61 29 2e 73 65 6c 65 63 74 20 7b 20 .to_a).select {
1350: 7c 63 7c 20 63 61 70 2e 69 6e 63 6c 75 64 65 73 |c| cap.includes
1360: 3f 28 63 29 20 7d 2e 6a 6f 69 6e 0a 65 6e 64 0a ?(c) }.join.end.
1370: 0a 23 20 53 74 6f 70 73 20 6f 6e 20 61 6e 20 53 .# Stops on an S
1380: 51 4c 69 74 65 20 65 72 72 6f 72 3b 20 61 20 6c QLite error; a l
1390: 6f 63 6b 20 69 73 20 72 65 70 6f 72 74 65 64 20 ock is reported
13a0: 61 70 61 72 74 2c 20 73 6f 20 74 68 65 20 63 61 apart, so the ca
13b0: 6c 6c 65 72 20 63 61 6e 20 77 61 69 74 2e 0a 64 ller can wait..d
13c0: 65 66 20 73 71 6c 69 74 65 28 64 62 20 3a 20 56 ef sqlite(db : V
13d0: 6f 69 64 2a 2c 20 63 6f 64 65 20 3a 20 49 6e 74 oid*, code : Int
13e0: 33 32 29 20 3a 20 4e 69 6c 0a 20 20 72 65 74 75 32) : Nil. retu
13f0: 72 6e 20 69 66 20 63 6f 64 65 20 3d 3d 20 30 0a rn if code == 0.
1400: 20 20 72 61 69 73 65 20 4c 6f 63 6b 65 64 2e 6e raise Locked.n
1410: 65 77 20 69 66 20 63 6f 64 65 20 3d 3d 20 35 20 ew if code == 5
1420: 7c 7c 20 63 6f 64 65 20 3d 3d 20 36 20 23 20 42 || code == 6 # B
1430: 55 53 59 2c 20 4c 4f 43 4b 45 44 0a 20 20 72 61 USY, LOCKED. ra
1440: 69 73 65 20 49 4f 3a 3a 45 72 72 6f 72 2e 6e 65 ise IO::Error.ne
1450: 77 28 22 73 71 6c 69 74 65 20 65 72 72 6f 72 20 w("sqlite error
1460: 23 7b 63 6f 64 65 7d 3a 20 23 7b 53 74 72 69 6e #{code}: #{Strin
1470: 67 2e 6e 65 77 28 4c 69 62 53 51 4c 69 74 65 33 g.new(LibSQLite3
1480: 2e 65 72 72 6d 73 67 28 64 62 29 29 7d 22 29 0a .errmsg(db))}").
1490: 65 6e 64 0a 0a 23 20 52 75 6e 73 20 6f 6e 65 20 end..# Runs one
14a0: 66 69 78 65 64 20 71 75 65 72 79 20 61 6e 64 20 fixed query and
14b0: 72 65 74 75 72 6e 73 20 69 74 73 20 72 6f 77 73 returns its rows
14c0: 2e 0a 64 65 66 20 72 6f 77 73 28 64 62 20 3a 20 ..def rows(db :
14d0: 56 6f 69 64 2a 2c 20 73 71 6c 20 3a 20 53 74 72 Void*, sql : Str
14e0: 69 6e 67 2c 20 76 61 6c 75 65 20 3a 20 53 74 72 ing, value : Str
14f0: 69 6e 67 3f 20 3d 20 6e 69 6c 29 20 3a 20 41 72 ing? = nil) : Ar
1500: 72 61 79 28 41 72 72 61 79 28 53 74 72 69 6e 67 ray(Array(String
1510: 3f 29 29 0a 20 20 73 74 61 74 65 6d 65 6e 74 20 ?)). statement
1520: 3d 20 50 6f 69 6e 74 65 72 28 56 6f 69 64 29 2e = Pointer(Void).
1530: 6e 75 6c 6c 0a 20 20 62 65 67 69 6e 0a 20 20 20 null. begin.
1540: 20 73 71 6c 69 74 65 28 64 62 2c 20 4c 69 62 53 sqlite(db, LibS
1550: 51 4c 69 74 65 33 2e 70 72 65 70 61 72 65 5f 76 QLite3.prepare_v
1560: 32 28 64 62 2c 20 73 71 6c 2c 20 2d 31 2c 20 70 2(db, sql, -1, p
1570: 6f 69 6e 74 65 72 6f 66 28 73 74 61 74 65 6d 65 ointerof(stateme
1580: 6e 74 29 2c 20 6e 69 6c 29 29 0a 20 20 20 20 73 nt), nil)). s
1590: 71 6c 69 74 65 28 64 62 2c 20 4c 69 62 53 51 4c qlite(db, LibSQL
15a0: 69 74 65 33 2e 62 69 6e 64 5f 74 65 78 74 28 73 ite3.bind_text(s
15b0: 74 61 74 65 6d 65 6e 74 2c 20 31 2c 20 76 61 6c tatement, 1, val
15c0: 75 65 2c 20 76 61 6c 75 65 2e 62 79 74 65 73 69 ue, value.bytesi
15d0: 7a 65 2c 20 50 6f 69 6e 74 65 72 28 56 6f 69 64 ze, Pointer(Void
15e0: 29 2e 6e 65 77 28 55 49 6e 74 36 34 3a 3a 4d 41 ).new(UInt64::MA
15f0: 58 29 29 29 20 69 66 20 76 61 6c 75 65 0a 20 20 X))) if value.
1600: 20 20 72 65 73 75 6c 74 20 3d 20 5b 5d 20 6f 66 result = [] of
1610: 20 41 72 72 61 79 28 53 74 72 69 6e 67 3f 29 0a Array(String?).
1620: 20 20 20 20 77 68 69 6c 65 20 28 63 6f 64 65 20 while (code
1630: 3d 20 4c 69 62 53 51 4c 69 74 65 33 2e 73 74 65 = LibSQLite3.ste
1640: 70 28 73 74 61 74 65 6d 65 6e 74 29 29 20 3d 3d p(statement)) ==
1650: 20 31 30 30 20 23 20 61 20 72 6f 77 0a 20 20 20 100 # a row.
1660: 20 20 20 72 65 73 75 6c 74 20 3c 3c 20 41 72 72 result << Arr
1670: 61 79 2e 6e 65 77 28 4c 69 62 53 51 4c 69 74 65 ay.new(LibSQLite
1680: 33 2e 63 6f 6c 75 6d 6e 5f 63 6f 75 6e 74 28 73 3.column_count(s
1690: 74 61 74 65 6d 65 6e 74 29 29 20 7b 20 7c 69 7c tatement)) { |i|
16a0: 20 74 65 78 74 28 73 74 61 74 65 6d 65 6e 74 2c text(statement,
16b0: 20 69 29 20 7d 0a 20 20 20 20 65 6e 64 0a 20 20 i) }. end.
16c0: 20 20 73 71 6c 69 74 65 28 64 62 2c 20 63 6f 64 sqlite(db, cod
16d0: 65 29 20 75 6e 6c 65 73 73 20 63 6f 64 65 20 3d e) unless code =
16e0: 3d 20 31 30 31 20 23 20 64 6f 6e 65 0a 20 20 20 = 101 # done.
16f0: 20 72 65 73 75 6c 74 0a 20 20 65 6e 73 75 72 65 result. ensure
1700: 0a 20 20 20 20 4c 69 62 53 51 4c 69 74 65 33 2e . LibSQLite3.
1710: 66 69 6e 61 6c 69 7a 65 28 73 74 61 74 65 6d 65 finalize(stateme
1720: 6e 74 29 0a 20 20 65 6e 64 0a 65 6e 64 0a 0a 64 nt). end.end..d
1730: 65 66 20 74 65 78 74 28 73 74 61 74 65 6d 65 6e ef text(statemen
1740: 74 20 3a 20 56 6f 69 64 2a 2c 20 63 6f 6c 75 6d t : Void*, colum
1750: 6e 20 3a 20 49 6e 74 33 32 29 20 3a 20 53 74 72 n : Int32) : Str
1760: 69 6e 67 3f 0a 20 20 74 20 3d 20 4c 69 62 53 51 ing?. t = LibSQ
1770: 4c 69 74 65 33 2e 63 6f 6c 75 6d 6e 5f 74 65 78 Lite3.column_tex
1780: 74 28 73 74 61 74 65 6d 65 6e 74 2c 20 63 6f 6c t(statement, col
1790: 75 6d 6e 29 0a 20 20 74 2e 6e 75 6c 6c 3f 20 3f umn). t.null? ?
17a0: 20 6e 69 6c 20 3a 20 53 74 72 69 6e 67 2e 6e 65 nil : String.ne
17b0: 77 28 74 29 0a 65 6e 64 0a 0a 23 20 4f 6e 65 20 w(t).end..# One
17c0: 72 65 61 64 2d 6f 6e 6c 79 20 73 6e 61 70 73 68 read-only snapsh
17d0: 6f 74 20 6f 66 20 77 68 61 74 20 74 68 65 20 72 ot of what the r
17e0: 65 70 6f 73 69 74 6f 72 79 20 73 61 79 73 2e 20 epository says.
17f0: 53 51 4c 69 74 65 27 73 20 6f 77 6e 20 6c 6f 63 SQLite's own loc
1800: 6b 69 6e 67 20 61 70 70 6c 69 65 73 3b 20 69 74 king applies; it
1810: 20 6e 65 76 65 72 20 77 61 69 74 73 20 69 74 73 never waits its
1820: 65 6c 66 2e 0a 64 65 66 20 72 65 61 64 28 70 61 elf..def read(pa
1830: 74 68 20 3a 20 53 74 72 69 6e 67 2c 20 63 61 70 th : String, cap
1840: 73 20 3a 20 53 74 72 69 6e 67 2c 20 72 65 71 75 s : String, requ
1850: 65 73 74 20 3a 20 52 65 71 75 65 73 74 29 20 3a est : Request) :
1860: 20 41 6e 73 77 65 72 0a 20 20 64 62 20 3d 20 50 Answer. db = P
1870: 6f 69 6e 74 65 72 28 56 6f 69 64 29 2e 6e 75 6c ointer(Void).nul
1880: 6c 0a 20 20 62 65 67 69 6e 0a 20 20 20 20 73 71 l. begin. sq
1890: 6c 69 74 65 28 64 62 2c 20 4c 69 62 53 51 4c 69 lite(db, LibSQLi
18a0: 74 65 33 2e 6f 70 65 6e 5f 76 32 28 22 66 69 6c te3.open_v2("fil
18b0: 65 3a 23 7b 55 52 49 2e 65 6e 63 6f 64 65 5f 70 e:#{URI.encode_p
18c0: 61 74 68 28 70 61 74 68 29 7d 3f 6d 6f 64 65 3d ath(path)}?mode=
18d0: 72 6f 22 2c 20 70 6f 69 6e 74 65 72 6f 66 28 64 ro", pointerof(d
18e0: 62 29 2c 20 30 78 30 31 20 7c 20 30 78 34 30 2c b), 0x01 | 0x40,
18f0: 20 6e 69 6c 29 29 20 23 20 72 65 61 64 2d 6f 6e nil)) # read-on
1900: 6c 79 2c 20 55 52 49 0a 20 20 20 20 73 6e 61 70 ly, URI. snap
1910: 73 68 6f 74 28 64 62 2c 20 63 61 70 73 2c 20 72 shot(db, caps, r
1920: 65 71 75 65 73 74 29 0a 20 20 65 6e 73 75 72 65 equest). ensure
1930: 0a 20 20 20 20 4c 69 62 53 51 4c 69 74 65 33 2e . LibSQLite3.
1940: 63 6c 6f 73 65 5f 76 32 28 64 62 29 0a 20 20 65 close_v2(db). e
1950: 6e 64 0a 65 6e 64 0a 0a 64 65 66 20 73 6e 61 70 nd.end..def snap
1960: 73 68 6f 74 28 64 62 20 3a 20 56 6f 69 64 2a 2c shot(db : Void*,
1970: 20 63 61 70 73 20 3a 20 53 74 72 69 6e 67 2c 20 caps : String,
1980: 72 65 71 75 65 73 74 20 3a 20 52 65 71 75 65 73 request : Reques
1990: 74 29 20 3a 20 41 6e 73 77 65 72 0a 20 20 73 71 t) : Answer. sq
19a0: 6c 69 74 65 28 64 62 2c 20 4c 69 62 53 51 4c 69 lite(db, LibSQLi
19b0: 74 65 33 2e 62 75 73 79 5f 74 69 6d 65 6f 75 74 te3.busy_timeout
19c0: 28 64 62 2c 20 30 29 29 0a 20 20 72 6f 77 73 28 (db, 0)). rows(
19d0: 64 62 2c 20 22 50 52 41 47 4d 41 20 71 75 65 72 db, "PRAGMA quer
19e0: 79 5f 6f 6e 6c 79 3d 31 22 29 0a 20 20 72 6f 77 y_only=1"). row
19f0: 73 28 64 62 2c 20 22 42 45 47 49 4e 22 29 0a 20 s(db, "BEGIN").
1a00: 20 73 70 65 63 69 61 6c 20 3d 20 72 6f 77 73 28 special = rows(
1a10: 64 62 2c 20 44 45 46 41 55 4c 54 53 29 2e 74 6f db, DEFAULTS).to
1a20: 5f 68 20 7b 20 7c 72 7c 20 7b 72 5b 30 5d 2e 74 _h { |r| {r[0].t
1a30: 6f 5f 73 2c 20 72 5b 31 5d 2e 74 6f 5f 73 7d 20 o_s, r[1].to_s}
1a40: 7d 0a 20 20 61 72 74 69 66 61 63 74 73 20 3d 20 }. artifacts =
1a50: 72 65 71 75 65 73 74 2e 61 72 74 69 66 61 63 74 request.artifact
1a60: 73 2e 6d 61 70 20 64 6f 20 7c 68 61 73 68 7c 0a s.map do |hash|.
1a70: 20 20 20 20 66 6f 75 6e 64 20 3d 20 41 72 74 69 found = Arti
1a80: 66 61 63 74 2e 6e 65 77 28 68 61 73 68 29 0a 20 fact.new(hash).
1a90: 20 20 20 69 66 20 28 72 20 3d 20 72 6f 77 73 28 if (r = rows(
1aa0: 64 62 2c 20 41 52 54 49 46 41 43 54 2c 20 68 61 db, ARTIFACT, ha
1ab0: 73 68 29 2e 66 69 72 73 74 3f 29 20 26 26 20 28 sh).first?) && (
1ac0: 72 5b 32 5d 20 3d 3d 20 22 30 22 20 7c 7c 20 63 r[2] == "0" || c
1ad0: 61 70 73 2e 69 6e 63 6c 75 64 65 73 3f 28 27 78 aps.includes?('x
1ae0: 27 29 29 20 23 20 70 72 69 76 61 74 65 20 6f 6e ')) # private on
1af0: 6c 79 20 66 6f 72 20 78 0a 20 20 20 20 20 20 66 ly for x. f
1b00: 6f 75 6e 64 2e 72 65 63 65 69 76 65 64 2c 20 66 ound.received, f
1b10: 6f 75 6e 64 2e 72 69 64 2c 20 66 6f 75 6e 64 2e ound.rid, found.
1b20: 72 65 63 65 69 70 74 20 3d 20 74 72 75 65 2c 20 receipt = true,
1b30: 72 5b 30 5d 2e 74 6f 5f 73 2e 74 6f 5f 69 36 34 r[0].to_s.to_i64
1b40: 2c 20 72 5b 31 5d 2e 74 6f 5f 73 2e 74 6f 5f 69 , r[1].to_s.to_i
1b50: 36 34 0a 20 20 20 20 20 20 66 6f 75 6e 64 2e 73 64. found.s
1b60: 65 6e 64 65 72 2c 20 66 6f 75 6e 64 2e 63 61 70 ender, found.cap
1b70: 61 62 69 6c 69 74 69 65 73 20 3d 20 72 5b 33 5d abilities = r[3]
1b80: 2c 20 65 78 70 61 6e 64 65 64 28 72 5b 34 5d 2e , expanded(r[4].
1b90: 74 6f 5f 73 2c 20 73 70 65 63 69 61 6c 29 20 69 to_s, special) i
1ba0: 66 20 72 5b 33 5d 0a 20 20 20 20 65 6e 64 0a 20 f r[3]. end.
1bb0: 20 20 20 66 6f 75 6e 64 0a 20 20 65 6e 64 0a 20 found. end.
1bc0: 20 75 73 65 72 20 3d 20 72 65 71 75 65 73 74 2e user = request.
1bd0: 63 61 70 61 62 69 6c 69 74 69 65 73 5f 6f 66 2e capabilities_of.
1be0: 74 72 79 20 64 6f 20 7c 6e 61 6d 65 7c 0a 20 20 try do |name|.
1bf0: 20 20 68 65 6c 64 20 3d 20 55 73 65 72 2e 6e 65 held = User.ne
1c00: 77 28 6e 61 6d 65 29 0a 20 20 20 20 69 66 20 72 w(name). if r
1c10: 20 3d 20 72 6f 77 73 28 64 62 2c 20 55 53 45 52 = rows(db, USER
1c20: 2c 20 6e 61 6d 65 29 2e 66 69 72 73 74 3f 0a 20 , name).first?.
1c30: 20 20 20 20 20 68 65 6c 64 2e 63 61 70 61 62 69 held.capabi
1c40: 6c 69 74 69 65 73 20 3d 20 65 78 70 61 6e 64 65 lities = expande
1c50: 64 28 72 5b 30 5d 2e 74 6f 5f 73 2c 20 73 70 65 d(r[0].to_s, spe
1c60: 63 69 61 6c 29 0a 20 20 20 20 20 20 6f 6e 20 3d cial). on =
1c70: 20 2d 3e 28 73 65 74 74 69 6e 67 20 3a 20 53 74 ->(setting : St
1c80: 72 69 6e 67 29 20 7b 20 7b 22 6f 6e 22 2c 20 22 ring) { {"on", "
1c90: 79 65 73 22 2c 20 22 74 72 75 65 22 2c 20 22 31 yes", "true", "1
1ca0: 22 7d 2e 69 6e 63 6c 75 64 65 73 3f 28 72 6f 77 "}.includes?(row
1cb0: 73 28 64 62 2c 20 53 45 54 54 49 4e 47 2c 20 73 s(db, SETTING, s
1cc0: 65 74 74 69 6e 67 29 2e 66 69 72 73 74 3f 2e 74 etting).first?.t
1cd0: 72 79 28 26 2e 66 69 72 73 74 29 2e 74 6f 5f 73 ry(&.first).to_s
1ce0: 2e 64 6f 77 6e 63 61 73 65 29 20 7d 0a 20 20 20 .downcase) }.
1cf0: 20 20 20 68 65 6c 64 2e 77 69 6b 69 5f 6d 6f 64 held.wiki_mod
1d00: 65 72 61 74 65 64 20 3d 20 6f 6e 2e 63 61 6c 6c erated = on.call
1d10: 28 22 6d 6f 64 72 65 71 2d 77 69 6b 69 22 29 20 ("modreq-wiki")
1d20: 26 26 20 21 68 65 6c 64 2e 63 61 70 61 62 69 6c && !held.capabil
1d30: 69 74 69 65 73 2e 74 6f 5f 73 2e 69 6e 63 6c 75 ities.to_s.inclu
1d40: 64 65 73 3f 28 27 6c 27 29 0a 20 20 20 20 20 20 des?('l').
1d50: 68 65 6c 64 2e 74 69 63 6b 65 74 5f 6d 6f 64 65 held.ticket_mode
1d60: 72 61 74 65 64 20 3d 20 6f 6e 2e 63 61 6c 6c 28 rated = on.call(
1d70: 22 6d 6f 64 72 65 71 2d 74 6b 74 22 29 20 26 26 "modreq-tkt") &&
1d80: 20 21 68 65 6c 64 2e 63 61 70 61 62 69 6c 69 74 !held.capabilit
1d90: 69 65 73 2e 74 6f 5f 73 2e 69 6e 63 6c 75 64 65 ies.to_s.include
1da0: 73 3f 28 27 71 27 29 0a 20 20 20 20 65 6e 64 0a s?('q'). end.
1db0: 20 20 20 20 68 65 6c 64 0a 20 20 65 6e 64 0a 20 held. end.
1dc0: 20 72 6f 77 73 28 64 62 2c 20 22 43 4f 4d 4d 49 rows(db, "COMMI
1dd0: 54 22 29 0a 20 20 41 6e 73 77 65 72 2e 6e 65 77 T"). Answer.new
1de0: 28 61 72 74 69 66 61 63 74 73 2c 20 75 73 65 72 (artifacts, user
1df0: 29 0a 65 6e 64 0a 0a 23 20 52 65 61 64 73 20 6f ).end..# Reads o
1e00: 6e 65 20 6c 69 6e 65 20 6f 66 20 61 74 20 6d 6f ne line of at mo
1e10: 73 74 20 60 6c 69 6d 69 74 60 20 62 79 74 65 73 st `limit` bytes
1e20: 20 62 65 66 6f 72 65 20 60 64 65 61 64 6c 69 6e before `deadlin
1e30: 65 60 2e 0a 64 65 66 20 6c 69 6e 65 28 73 6f 63 e`..def line(soc
1e40: 6b 65 74 20 3a 20 55 4e 49 58 53 6f 63 6b 65 74 ket : UNIXSocket
1e50: 2c 20 6c 69 6d 69 74 20 3a 20 49 6e 74 33 32 2c , limit : Int32,
1e60: 20 64 65 61 64 6c 69 6e 65 20 3a 20 54 69 6d 65 deadline : Time
1e70: 29 20 3a 20 53 74 72 69 6e 67 0a 20 20 74 65 78 ) : String. tex
1e80: 74 20 3d 20 49 4f 3a 3a 4d 65 6d 6f 72 79 2e 6e t = IO::Memory.n
1e90: 65 77 0a 20 20 6c 6f 6f 70 20 64 6f 0a 20 20 20 ew. loop do.
1ea0: 20 73 6f 63 6b 65 74 2e 72 65 61 64 5f 74 69 6d socket.read_tim
1eb0: 65 6f 75 74 20 3d 20 7b 64 65 61 64 6c 69 6e 65 eout = {deadline
1ec0: 20 2d 20 54 69 6d 65 2e 75 74 63 2c 20 31 2e 6d - Time.utc, 1.m
1ed0: 69 6c 6c 69 73 65 63 6f 6e 64 7d 2e 6d 61 78 0a illisecond}.max.
1ee0: 20 20 20 20 62 79 74 65 20 3d 20 73 6f 63 6b 65 byte = socke
1ef0: 74 2e 72 65 61 64 5f 62 79 74 65 20 7c 7c 20 72 t.read_byte || r
1f00: 61 69 73 65 20 52 65 66 75 73 65 64 2e 6e 65 77 aise Refused.new
1f10: 28 22 65 78 70 65 63 74 65 64 20 74 77 6f 20 4a ("expected two J
1f20: 53 4f 4e 20 6c 69 6e 65 73 22 29 0a 20 20 20 20 SON lines").
1f30: 72 65 74 75 72 6e 20 74 65 78 74 2e 74 6f 5f 73 return text.to_s
1f40: 20 69 66 20 62 79 74 65 20 3d 3d 20 31 30 0a 20 if byte == 10.
1f50: 20 20 20 72 61 69 73 65 20 52 65 66 75 73 65 64 raise Refused
1f60: 2e 6e 65 77 28 22 6c 69 6e 65 20 74 6f 6f 20 6c .new("line too l
1f70: 6f 6e 67 22 29 20 69 66 20 74 65 78 74 2e 73 69 ong") if text.si
1f80: 7a 65 20 3e 3d 20 6c 69 6d 69 74 0a 20 20 20 20 ze >= limit.
1f90: 74 65 78 74 2e 77 72 69 74 65 5f 62 79 74 65 28 text.write_byte(
1fa0: 62 79 74 65 29 0a 20 20 65 6e 64 0a 72 65 73 63 byte). end.resc
1fb0: 75 65 20 49 4f 3a 3a 54 69 6d 65 6f 75 74 45 72 ue IO::TimeoutEr
1fc0: 72 6f 72 0a 20 20 72 61 69 73 65 20 52 65 66 75 ror. raise Refu
1fd0: 73 65 64 2e 6e 65 77 28 22 72 65 71 75 65 73 74 sed.new("request
1fe0: 20 6e 6f 74 20 72 65 63 65 69 76 65 64 20 77 69 not received wi
1ff0: 74 68 69 6e 20 23 7b 52 45 41 44 5f 57 49 54 48 thin #{READ_WITH
2000: 49 4e 2e 74 6f 74 61 6c 5f 73 65 63 6f 6e 64 73 IN.total_seconds
2010: 2e 74 6f 5f 69 7d 20 73 22 29 0a 65 6e 64 0a 0a .to_i} s").end..
2020: 23 20 41 6e 73 77 65 72 73 20 6f 6e 65 20 63 6f # Answers one co
2030: 6e 6e 65 63 74 69 6f 6e 2c 20 74 68 65 6e 20 63 nnection, then c
2040: 6c 6f 73 65 73 20 69 74 20 61 6e 64 20 6c 6f 67 loses it and log
2050: 73 20 6f 6e 65 20 6c 69 6e 65 2e 0a 64 65 66 20 s one line..def
2060: 73 65 72 76 65 28 73 6f 63 6b 65 74 20 3a 20 55 serve(socket : U
2070: 4e 49 58 53 6f 63 6b 65 74 2c 20 73 74 61 72 74 NIXSocket, start
2080: 65 64 20 3a 20 54 69 6d 65 29 20 3a 20 4e 69 6c ed : Time) : Nil
2090: 0a 20 20 6e 61 6d 65 2c 20 6f 75 74 63 6f 6d 65 . name, outcome
20a0: 20 3d 20 22 2d 22 2c 20 22 6f 6b 22 0a 20 20 61 = "-", "ok". a
20b0: 6e 73 77 65 72 20 3d 20 62 65 67 69 6e 0a 20 20 nswer = begin.
20c0: 20 20 63 72 65 64 73 20 3d 20 53 74 61 74 69 63 creds = Static
20d0: 41 72 72 61 79 28 55 49 6e 74 33 32 2c 20 33 29 Array(UInt32, 3)
20e0: 2e 6e 65 77 28 30 29 20 23 20 53 4f 5f 50 45 45 .new(0) # SO_PEE
20f0: 52 43 52 45 44 3a 20 70 69 64 2c 20 75 69 64 2c RCRED: pid, uid,
2100: 20 67 69 64 0a 20 20 20 20 73 69 7a 65 20 3d 20 gid. size =
2110: 73 69 7a 65 6f 66 28 74 79 70 65 6f 66 28 63 72 sizeof(typeof(cr
2120: 65 64 73 29 29 2e 74 6f 5f 75 33 32 0a 20 20 20 eds)).to_u32.
2130: 20 72 61 69 73 65 20 52 65 66 75 73 65 64 2e 6e raise Refused.n
2140: 65 77 28 22 70 65 65 72 20 75 69 64 20 64 69 66 ew("peer uid dif
2150: 66 65 72 73 22 29 20 75 6e 6c 65 73 73 20 4c 69 fers") unless Li
2160: 62 43 2e 67 65 74 73 6f 63 6b 6f 70 74 28 73 6f bC.getsockopt(so
2170: 63 6b 65 74 2e 66 64 2c 20 31 2c 20 31 37 2c 20 cket.fd, 1, 17,
2180: 70 6f 69 6e 74 65 72 6f 66 28 63 72 65 64 73 29 pointerof(creds)
2190: 2c 20 70 6f 69 6e 74 65 72 6f 66 28 73 69 7a 65 , pointerof(size
21a0: 29 29 20 3d 3d 20 30 20 26 26 20 63 72 65 64 73 )) == 0 && creds
21b0: 5b 31 5d 20 3d 3d 20 4c 69 62 43 2e 67 65 74 75 [1] == LibC.getu
21c0: 69 64 0a 20 20 20 20 69 64 65 6e 74 69 74 79 20 id. identity
21d0: 3d 20 49 64 65 6e 74 69 74 79 2e 66 72 6f 6d 5f = Identity.from_
21e0: 6a 73 6f 6e 28 6c 69 6e 65 28 73 6f 63 6b 65 74 json(line(socket
21f0: 2c 20 31 30 32 34 2c 20 73 74 61 72 74 65 64 20 , 1024, started
2200: 2b 20 52 45 41 44 5f 57 49 54 48 49 4e 29 29 0a + READ_WITHIN)).
2210: 20 20 20 20 72 65 71 75 65 73 74 20 3d 20 52 65 request = Re
2220: 71 75 65 73 74 2e 66 72 6f 6d 5f 6a 73 6f 6e 28 quest.from_json(
2230: 6c 69 6e 65 28 73 6f 63 6b 65 74 2c 20 38 31 39 line(socket, 819
2240: 32 2c 20 73 74 61 72 74 65 64 20 2b 20 52 45 41 2, started + REA
2250: 44 5f 57 49 54 48 49 4e 29 29 0a 20 20 20 20 6e D_WITHIN)). n
2260: 61 6d 65 20 3d 20 69 64 65 6e 74 69 74 79 2e 72 ame = identity.r
2270: 65 70 6f 73 69 74 6f 72 79 0a 20 20 20 20 70 61 epository. pa
2280: 74 68 20 3d 20 46 69 6c 65 2e 6a 6f 69 6e 28 52 th = File.join(R
2290: 45 50 4f 53 49 54 4f 52 49 45 53 2c 20 6e 61 6d EPOSITORIES, nam
22a0: 65 20 2b 20 22 2e 66 6f 73 73 69 6c 22 29 0a 20 e + ".fossil").
22b0: 20 20 20 72 61 69 73 65 20 52 65 66 75 73 65 64 raise Refused
22c0: 2e 6e 65 77 28 22 69 6e 76 61 6c 69 64 20 72 65 .new("invalid re
22d0: 70 6f 73 69 74 6f 72 79 22 29 20 75 6e 6c 65 73 pository") unles
22e0: 73 20 6e 61 6d 65 2e 6d 61 74 63 68 65 73 3f 28 s name.matches?(
22f0: 2f 5c 41 5b 41 2d 5a 61 2d 7a 30 2d 39 5f 5d 5b /\A[A-Za-z0-9_][
2300: 41 2d 5a 61 2d 7a 30 2d 39 2e 5f 2d 5d 7b 30 2c A-Za-z0-9._-]{0,
2310: 39 39 7d 5c 7a 2f 29 20 26 26 20 46 69 6c 65 2e 99}\z/) && File.
2320: 66 69 6c 65 3f 28 70 61 74 68 29 0a 20 20 20 20 file?(path).
2330: 72 61 69 73 65 20 52 65 66 75 73 65 64 2e 6e 65 raise Refused.ne
2340: 77 28 22 69 6e 76 61 6c 69 64 20 6f 63 78 5f 72 w("invalid ocx_r
2350: 65 63 65 69 70 74 22 29 20 75 6e 6c 65 73 73 20 eceipt") unless
2360: 72 65 71 75 65 73 74 2e 6f 63 78 5f 72 65 63 65 request.ocx_rece
2370: 69 70 74 20 3d 3d 20 31 0a 20 20 20 20 72 61 69 ipt == 1. rai
2380: 73 65 20 52 65 66 75 73 65 64 2e 6e 65 77 28 22 se Refused.new("
2390: 69 6e 76 61 6c 69 64 20 61 72 74 69 66 61 63 74 invalid artifact
23a0: 73 22 29 20 75 6e 6c 65 73 73 20 72 65 71 75 65 s") unless reque
23b0: 73 74 2e 61 72 74 69 66 61 63 74 73 2e 73 69 7a st.artifacts.siz
23c0: 65 20 3c 3d 20 36 34 20 26 26 20 72 65 71 75 65 e <= 64 && reque
23d0: 73 74 2e 61 72 74 69 66 61 63 74 73 2e 61 6c 6c st.artifacts.all
23e0: 3f 28 26 2e 6d 61 74 63 68 65 73 3f 28 2f 5c 41 ?(&.matches?(/\A
23f0: 28 5b 30 2d 39 61 2d 66 5d 7b 34 30 7d 7c 5b 30 ([0-9a-f]{40}|[0
2400: 2d 39 61 2d 66 5d 7b 36 34 7d 29 5c 7a 2f 29 29 -9a-f]{64})\z/))
2410: 0a 20 20 20 20 72 61 69 73 65 20 52 65 66 75 73 . raise Refus
2420: 65 64 2e 6e 65 77 28 22 69 6e 76 61 6c 69 64 20 ed.new("invalid
2430: 63 61 70 61 62 69 6c 69 74 69 65 73 5f 6f 66 22 capabilities_of"
2440: 29 20 69 66 20 72 65 71 75 65 73 74 2e 63 61 70 ) if request.cap
2450: 61 62 69 6c 69 74 69 65 73 5f 6f 66 2e 74 72 79 abilities_of.try
2460: 20 7b 20 7c 75 7c 20 75 2e 73 69 7a 65 20 3e 20 { |u| u.size >
2470: 31 30 30 20 7c 7c 20 75 2e 65 61 63 68 5f 63 68 100 || u.each_ch
2480: 61 72 2e 61 6e 79 3f 28 26 2e 63 6f 6e 74 72 6f ar.any?(&.contro
2490: 6c 3f 29 20 7d 0a 20 20 20 20 69 66 20 21 69 64 l?) }. if !id
24a0: 65 6e 74 69 74 79 2e 63 61 70 61 62 69 6c 69 74 entity.capabilit
24b0: 69 65 73 2e 69 6e 63 6c 75 64 65 73 3f 28 27 6f ies.includes?('o
24c0: 27 29 20 23 20 6e 6f 20 52 65 61 64 3a 20 6e 6f ') # no Read: no
24d0: 74 68 69 6e 67 20 63 6f 75 6e 74 73 20 61 73 20 thing counts as
24e0: 72 65 63 65 69 76 65 64 2c 20 61 6e 64 20 6e 6f received, and no
24f0: 74 68 69 6e 67 20 69 73 20 72 65 61 64 0a 20 20 thing is read.
2500: 20 20 20 20 41 6e 73 77 65 72 2e 6e 65 77 28 72 Answer.new(r
2510: 65 71 75 65 73 74 2e 61 72 74 69 66 61 63 74 73 equest.artifacts
2520: 2e 6d 61 70 20 7b 20 7c 68 7c 20 41 72 74 69 66 .map { |h| Artif
2530: 61 63 74 2e 6e 65 77 28 68 29 20 7d 2c 20 72 65 act.new(h) }, re
2540: 71 75 65 73 74 2e 63 61 70 61 62 69 6c 69 74 69 quest.capabiliti
2550: 65 73 5f 6f 66 2e 74 72 79 20 7b 20 7c 75 7c 20 es_of.try { |u|
2560: 55 73 65 72 2e 6e 65 77 28 75 29 20 7d 29 2e 74 User.new(u) }).t
2570: 6f 5f 6a 73 6f 6e 0a 20 20 20 20 65 6c 73 65 0a o_json. else.
2580: 20 20 20 20 20 20 67 69 76 65 5f 75 70 20 3d 20 give_up =
2590: 54 69 6d 65 2e 75 74 63 20 2b 20 4c 4f 43 4b 5f Time.utc + LOCK_
25a0: 57 41 49 54 0a 20 20 20 20 20 20 6c 6f 6f 70 20 WAIT. loop
25b0: 64 6f 0a 20 20 20 20 20 20 20 20 62 72 65 61 6b do. break
25c0: 20 72 65 61 64 28 70 61 74 68 2c 20 69 64 65 6e read(path, iden
25d0: 74 69 74 79 2e 63 61 70 61 62 69 6c 69 74 69 65 tity.capabilitie
25e0: 73 2c 20 72 65 71 75 65 73 74 29 2e 74 6f 5f 6a s, request).to_j
25f0: 73 6f 6e 0a 20 20 20 20 20 20 72 65 73 63 75 65 son. rescue
2600: 20 4c 6f 63 6b 65 64 0a 20 20 20 20 20 20 20 20 Locked.
2610: 72 61 69 73 65 20 49 4f 3a 3a 45 72 72 6f 72 2e raise IO::Error.
2620: 6e 65 77 28 22 73 71 6c 69 74 65 20 65 72 72 6f new("sqlite erro
2630: 72 20 35 3a 20 64 61 74 61 62 61 73 65 20 69 73 r 5: database is
2640: 20 6c 6f 63 6b 65 64 22 29 20 69 66 20 54 69 6d locked") if Tim
2650: 65 2e 75 74 63 20 3e 3d 20 67 69 76 65 5f 75 70 e.utc >= give_up
2660: 0a 20 20 20 20 20 20 20 20 73 6c 65 65 70 20 35 . sleep 5
2670: 30 2e 6d 69 6c 6c 69 73 65 63 6f 6e 64 73 20 23 0.milliseconds #
2680: 20 77 61 69 74 69 6e 67 20 68 65 72 65 20 6c 65 waiting here le
2690: 74 73 20 6f 74 68 65 72 20 63 6f 6e 6e 65 63 74 ts other connect
26a0: 69 6f 6e 73 20 67 6f 20 6f 6e 0a 20 20 20 20 20 ions go on.
26b0: 20 65 6e 64 0a 20 20 20 20 65 6e 64 0a 20 20 72 end. end. r
26c0: 65 73 63 75 65 20 65 78 20 3a 20 52 65 66 75 73 escue ex : Refus
26d0: 65 64 20 7c 20 4a 53 4f 4e 3a 3a 53 65 72 69 61 ed | JSON::Seria
26e0: 6c 69 7a 61 62 6c 65 45 72 72 6f 72 20 7c 20 4a lizableError | J
26f0: 53 4f 4e 3a 3a 50 61 72 73 65 45 78 63 65 70 74 SON::ParseExcept
2700: 69 6f 6e 0a 20 20 20 20 6f 75 74 63 6f 6d 65 20 ion. outcome
2710: 3d 20 22 72 65 66 75 73 65 64 22 0a 20 20 20 20 = "refused".
2720: 7b 72 65 66 75 73 65 64 3a 20 65 78 2e 69 73 5f {refused: ex.is_
2730: 61 3f 28 52 65 66 75 73 65 64 29 20 3f 20 65 78 a?(Refused) ? ex
2740: 2e 6d 65 73 73 61 67 65 20 3a 20 22 69 6e 76 61 .message : "inva
2750: 6c 69 64 20 4a 53 4f 4e 3a 20 23 7b 65 78 2e 6d lid JSON: #{ex.m
2760: 65 73 73 61 67 65 2e 74 6f 5f 73 2e 6c 69 6e 65 essage.to_s.line
2770: 73 2e 66 69 72 73 74 3f 7d 22 7d 2e 74 6f 5f 6a s.first?}"}.to_j
2780: 73 6f 6e 0a 20 20 72 65 73 63 75 65 20 65 78 0a son. rescue ex.
2790: 20 20 20 20 6f 75 74 63 6f 6d 65 20 3d 20 22 75 outcome = "u
27a0: 6e 61 76 61 69 6c 61 62 6c 65 22 0a 20 20 20 20 navailable".
27b0: 7b 75 6e 61 76 61 69 6c 61 62 6c 65 3a 20 65 78 {unavailable: ex
27c0: 2e 69 73 5f 61 3f 28 49 4f 3a 3a 45 72 72 6f 72 .is_a?(IO::Error
27d0: 29 20 3f 20 65 78 2e 6d 65 73 73 61 67 65 20 3a ) ? ex.message :
27e0: 20 22 69 6e 74 65 72 6e 61 6c 20 65 72 72 6f 72 "internal error
27f0: 22 2c 20 72 65 74 72 79 5f 61 66 74 65 72 3a 20 ", retry_after:
2800: 31 7d 2e 74 6f 5f 6a 73 6f 6e 0a 20 20 65 6e 64 1}.to_json. end
2810: 0a 20 20 73 6f 63 6b 65 74 2e 77 72 69 74 65 5f . socket.write_
2820: 74 69 6d 65 6f 75 74 20 3d 20 32 2e 73 65 63 6f timeout = 2.seco
2830: 6e 64 73 0a 20 20 73 6f 63 6b 65 74 2e 70 75 74 nds. socket.put
2840: 73 28 61 6e 73 77 65 72 29 0a 72 65 73 63 75 65 s(answer).rescue
2850: 20 49 4f 3a 3a 45 72 72 6f 72 20 23 20 74 68 65 IO::Error # the
2860: 20 63 61 6c 6c 65 72 20 6c 65 66 74 0a 65 6e 73 caller left.ens
2870: 75 72 65 0a 20 20 73 6f 63 6b 65 74 2e 63 6c 6f ure. socket.clo
2880: 73 65 0a 20 20 53 54 44 45 52 52 2e 70 75 74 73 se. STDERR.puts
2890: 20 22 23 7b 54 69 6d 65 2e 75 74 63 2e 74 6f 5f "#{Time.utc.to_
28a0: 72 66 63 33 33 33 39 7d 20 23 7b 6e 61 6d 65 7d rfc3339} #{name}
28b0: 20 23 7b 6f 75 74 63 6f 6d 65 7d 20 23 7b 28 54 #{outcome} #{(T
28c0: 69 6d 65 2e 75 74 63 20 2d 20 73 74 61 72 74 65 ime.utc - starte
28d0: 64 29 2e 74 6f 74 61 6c 5f 6d 69 6c 6c 69 73 65 d).total_millise
28e0: 63 6f 6e 64 73 2e 74 6f 5f 69 7d 6d 73 22 0a 65 conds.to_i}ms".e
28f0: 6e 64 0a 0a 23 20 4c 69 73 74 65 6e 20 61 74 20 nd..# Listen at
2900: 74 68 65 20 66 69 78 65 64 20 73 6f 63 6b 65 74 the fixed socket
2910: 3b 20 65 61 63 68 20 63 6f 6e 6e 65 63 74 69 6f ; each connectio
2920: 6e 20 69 73 20 73 65 72 76 65 64 20 6f 6e 20 69 n is served on i
2930: 74 73 20 6f 77 6e 2c 20 73 6f 20 6f 6e 65 20 6c ts own, so one l
2940: 6f 63 6b 20 6e 65 76 65 72 20 68 6f 6c 64 73 20 ock never holds
2950: 75 70 20 61 6e 6f 74 68 65 72 2e 0a 46 69 6c 65 up another..File
2960: 2e 64 65 6c 65 74 65 28 53 4f 43 4b 45 54 29 20 .delete(SOCKET)
2970: 69 66 20 46 69 6c 65 2e 65 78 69 73 74 73 3f 28 if File.exists?(
2980: 53 4f 43 4b 45 54 29 0a 73 65 72 76 65 72 20 3d SOCKET).server =
2990: 20 55 4e 49 58 53 65 72 76 65 72 2e 6e 65 77 28 UNIXServer.new(
29a0: 53 4f 43 4b 45 54 29 0a 46 69 6c 65 2e 63 68 6d SOCKET).File.chm
29b0: 6f 64 28 53 4f 43 4b 45 54 2c 20 30 6f 36 30 30 od(SOCKET, 0o600
29c0: 29 0a 77 68 69 6c 65 20 73 6f 63 6b 65 74 20 3d ).while socket =
29d0: 20 73 65 72 76 65 72 2e 61 63 63 65 70 74 3f 0a server.accept?.
29e0: 20 20 73 70 61 77 6e 20 73 65 72 76 65 28 73 6f spawn serve(so
29f0: 63 6b 65 74 2c 20 54 69 6d 65 2e 75 74 63 29 0a cket, Time.utc).
2a00: 65 6e 64 0a 00 00 00 00 00 00 00 00 00 00 00 00 end.............
2a10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2a20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2a30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2a40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2a50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2a60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2a70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2a80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2a90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2aa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2ab0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2ac0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2ad0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2ae0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2af0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2b00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2b10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2b20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2b30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2b40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2b50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2b60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2b70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2b90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2ba0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2bb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2bc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2bd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2be0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2bf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2c00: 73 63 72 69 70 74 73 2d 66 6f 72 2d 72 65 76 69 scripts-for-revi
2c10: 65 77 2d 33 2f 73 74 61 72 74 2d 66 6f 73 73 69 ew-3/start-fossi
2c20: 6c 2e 63 72 00 00 00 00 00 00 00 00 00 00 00 00 l.cr............
2c30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2c40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2c50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2c60: 00 00 00 00 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000
2c70: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
2c80: 30 30 30 34 37 36 33 00 31 35 32 37 30 36 36 34 0004763.15270664
2c90: 36 31 33 00 30 31 36 34 37 32 00 20 30 00 00 00 613.016472. 0...
2ca0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2cb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2cc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2cd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2ce0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2cf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2d00: 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
2d10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2d20: 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
2d30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2d40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2d50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2d60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2d70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2d90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2da0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2db0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2dc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2dd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2de0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2df0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
2e00: 23 20 41 67 65 6e 74 73 3a 20 64 6f 20 6e 6f 74 # Agents: do not
2e10: 20 63 68 61 6e 67 65 20 74 68 69 73 20 66 69 6c change this fil
2e20: 65 20 6f 6e 20 61 6e 79 20 62 72 61 6e 63 68 20 e on any branch
2e30: 77 69 74 68 6f 75 74 20 74 68 65 20 6d 61 69 6e without the main
2e40: 74 61 69 6e 65 72 27 73 20 65 78 70 6c 69 63 69 tainer's explici
2e50: 74 20 61 70 70 72 6f 76 61 6c 20 6f 6e 20 74 68 t approval on th
2e60: 65 20 72 65 63 6f 72 64 2e 0a 23 20 53 74 61 72 e record..# Star
2e70: 74 20 46 6f 73 73 69 6c 3b 20 73 65 74 74 69 6e t Fossil; settin
2e80: 67 73 20 61 72 65 20 69 6e 20 74 68 65 20 73 65 gs are in the se
2e90: 72 76 65 72 73 2e 6a 73 6f 6e 20 62 65 73 69 64 rvers.json besid
2ea0: 65 20 74 68 69 73 20 70 72 6f 67 72 61 6d 2e 0a e this program..
2eb0: 23 20 54 68 65 20 6d 61 69 6e 74 61 69 6e 65 72 # The maintainer
2ec0: 20 72 75 6e 73 20 62 69 6e 2f 73 74 61 72 74 2d runs bin/start-
2ed0: 66 6f 73 73 69 6c 20 61 66 74 65 72 20 73 68 61 fossil after sha
2ee0: 72 64 73 20 62 75 69 6c 64 20 73 74 61 72 74 2d rds build start-
2ef0: 66 6f 73 73 69 6c 2e 0a 72 65 71 75 69 72 65 20 fossil..require
2f00: 22 6a 73 6f 6e 22 0a 0a 73 74 72 75 63 74 20 46 "json"..struct F
2f10: 6f 73 73 69 6c 53 65 72 76 65 72 0a 20 20 69 6e ossilServer. in
2f20: 63 6c 75 64 65 20 4a 53 4f 4e 3a 3a 53 65 72 69 clude JSON::Seri
2f30: 61 6c 69 7a 61 62 6c 65 0a 20 20 67 65 74 74 65 alizable. gette
2f40: 72 20 66 6f 73 73 69 6c 20 3a 20 53 74 72 69 6e r fossil : Strin
2f50: 67 20 3d 20 22 66 6f 73 73 69 6c 22 0a 20 20 67 g = "fossil". g
2f60: 65 74 74 65 72 20 61 72 67 73 20 3a 20 41 72 72 etter args : Arr
2f70: 61 79 28 53 74 72 69 6e 67 29 0a 20 20 67 65 74 ay(String). get
2f80: 74 65 72 20 73 68 6f 77 5f 63 61 70 61 62 69 6c ter show_capabil
2f90: 69 74 69 65 73 20 3a 20 42 6f 6f 6c 20 3d 20 66 ities : Bool = f
2fa0: 61 6c 73 65 0a 65 6e 64 0a 0a 73 74 72 75 63 74 alse.end..struct
2fb0: 20 4f 43 58 0a 20 20 69 6e 63 6c 75 64 65 20 4a OCX. include J
2fc0: 53 4f 4e 3a 3a 53 65 72 69 61 6c 69 7a 61 62 6c SON::Serializabl
2fd0: 65 0a 20 20 67 65 74 74 65 72 20 6c 61 75 6e 63 e. getter launc
2fe0: 68 65 72 20 3a 20 53 74 72 69 6e 67 3f 0a 65 6e her : String?.en
2ff0: 64 0a 0a 73 74 72 75 63 74 20 53 65 72 76 65 72 d..struct Server
3000: 0a 20 20 69 6e 63 6c 75 64 65 20 4a 53 4f 4e 3a . include JSON:
3010: 3a 53 65 72 69 61 6c 69 7a 61 62 6c 65 0a 20 20 :Serializable.
3020: 67 65 74 74 65 72 20 66 6f 73 73 69 6c 5f 73 65 getter fossil_se
3030: 72 76 65 72 20 3a 20 46 6f 73 73 69 6c 53 65 72 rver : FossilSer
3040: 76 65 72 3f 0a 20 20 67 65 74 74 65 72 20 6f 63 ver?. getter oc
3050: 78 20 3a 20 4f 43 58 3f 0a 65 6e 64 0a 0a 23 20 x : OCX?.end..#
3060: 53 65 6c 65 63 74 20 65 61 63 68 20 70 61 72 74 Select each part
3070: 20 66 72 6f 6d 20 74 68 69 73 20 68 6f 73 74 2c from this host,
3080: 20 74 68 65 6e 20 74 68 65 20 64 65 66 61 75 6c then the defaul
3090: 74 20 65 6e 74 72 79 2e 0a 66 69 6c 65 20 3d 20 t entry..file =
30a0: 46 69 6c 65 2e 6a 6f 69 6e 28 46 69 6c 65 2e 64 File.join(File.d
30b0: 69 72 6e 61 6d 65 28 50 72 6f 63 65 73 73 2e 65 irname(Process.e
30c0: 78 65 63 75 74 61 62 6c 65 5f 70 61 74 68 2e 6e xecutable_path.n
30d0: 6f 74 5f 6e 69 6c 21 29 2c 20 22 73 65 72 76 65 ot_nil!), "serve
30e0: 72 73 2e 6a 73 6f 6e 22 29 0a 62 65 67 69 6e 0a rs.json").begin.
30f0: 20 20 73 65 72 76 65 72 73 20 3d 20 48 61 73 68 servers = Hash
3100: 28 53 74 72 69 6e 67 2c 20 4a 53 4f 4e 3a 3a 41 (String, JSON::A
3110: 6e 79 29 2e 66 72 6f 6d 5f 6a 73 6f 6e 28 46 69 ny).from_json(Fi
3120: 6c 65 2e 72 65 61 64 28 66 69 6c 65 29 29 0a 20 le.read(file)).
3130: 20 6c 6f 63 61 6c 20 3d 20 73 65 72 76 65 72 73 local = servers
3140: 5b 53 79 73 74 65 6d 2e 68 6f 73 74 6e 61 6d 65 [System.hostname
3150: 5d 3f 2e 74 72 79 20 7b 20 7c 65 6e 74 72 79 7c ]?.try { |entry|
3160: 20 53 65 72 76 65 72 2e 66 72 6f 6d 5f 6a 73 6f Server.from_jso
3170: 6e 28 65 6e 74 72 79 2e 74 6f 5f 6a 73 6f 6e 29 n(entry.to_json)
3180: 20 7d 0a 20 20 64 65 66 61 75 6c 74 20 3d 20 73 }. default = s
3190: 65 72 76 65 72 73 5b 22 2a 22 5d 3f 2e 74 72 79 ervers["*"]?.try
31a0: 20 7b 20 7c 65 6e 74 72 79 7c 20 53 65 72 76 65 { |entry| Serve
31b0: 72 2e 66 72 6f 6d 5f 6a 73 6f 6e 28 65 6e 74 72 r.from_json(entr
31c0: 79 2e 74 6f 5f 6a 73 6f 6e 29 20 7d 0a 20 20 73 y.to_json) }. s
31d0: 65 74 74 69 6e 67 73 20 3d 20 6c 6f 63 61 6c 2e ettings = local.
31e0: 74 72 79 28 26 2e 66 6f 73 73 69 6c 5f 73 65 72 try(&.fossil_ser
31f0: 76 65 72 29 20 7c 7c 20 64 65 66 61 75 6c 74 2e ver) || default.
3200: 74 72 79 28 26 2e 66 6f 73 73 69 6c 5f 73 65 72 try(&.fossil_ser
3210: 76 65 72 29 20 7c 7c 20 61 62 6f 72 74 20 22 23 ver) || abort "#
3220: 7b 66 69 6c 65 7d 3a 20 6d 69 73 73 69 6e 67 20 {file}: missing
3230: 66 6f 73 73 69 6c 5f 73 65 72 76 65 72 22 2c 20 fossil_server",
3240: 32 0a 72 65 73 63 75 65 20 65 78 20 3a 20 49 4f 2.rescue ex : IO
3250: 3a 3a 45 72 72 6f 72 20 7c 20 4a 53 4f 4e 3a 3a ::Error | JSON::
3260: 50 61 72 73 65 45 78 63 65 70 74 69 6f 6e 0a 20 ParseException.
3270: 20 61 62 6f 72 74 20 22 23 7b 66 69 6c 65 7d 3a abort "#{file}:
3280: 20 63 61 6e 6e 6f 74 20 72 65 61 64 20 66 6f 73 cannot read fos
3290: 73 69 6c 5f 73 65 72 76 65 72 3a 20 23 7b 65 78 sil_server: #{ex
32a0: 2e 6d 65 73 73 61 67 65 2e 74 6f 5f 73 2e 6c 69 .message.to_s.li
32b0: 6e 65 73 2e 66 69 72 73 74 7d 22 2c 20 32 0a 65 nes.first}", 2.e
32c0: 6e 64 0a 62 61 73 65 64 69 72 20 3d 20 46 69 6c nd.basedir = Fil
32d0: 65 2e 72 65 61 6c 70 61 74 68 28 46 69 6c 65 2e e.realpath(File.
32e0: 6a 6f 69 6e 28 46 69 6c 65 2e 64 69 72 6e 61 6d join(File.dirnam
32f0: 65 28 50 72 6f 63 65 73 73 2e 65 78 65 63 75 74 e(Process.execut
3300: 61 62 6c 65 5f 70 61 74 68 2e 6e 6f 74 5f 6e 69 able_path.not_ni
3310: 6c 21 29 2c 20 22 2e 2e 2f 2e 2e 22 29 29 0a 0a l!), "../.."))..
3320: 64 65 66 20 65 78 70 61 6e 64 28 74 65 78 74 20 def expand(text
3330: 3a 20 53 74 72 69 6e 67 2c 20 62 61 73 65 64 69 : String, basedi
3340: 72 20 3a 20 53 74 72 69 6e 67 29 20 3a 20 53 74 r : String) : St
3350: 72 69 6e 67 0a 20 20 74 65 78 74 2e 67 73 75 62 ring. text.gsub
3360: 28 2f 5c 24 48 4f 4d 45 7c 5c 24 42 41 53 45 44 (/\$HOME|\$BASED
3370: 49 52 2f 29 20 7b 20 7c 6e 61 6d 65 7c 20 6e 61 IR/) { |name| na
3380: 6d 65 20 3d 3d 20 22 24 48 4f 4d 45 22 20 3f 20 me == "$HOME" ?
3390: 45 4e 56 5b 22 48 4f 4d 45 22 5d 20 3a 20 62 61 ENV["HOME"] : ba
33a0: 73 65 64 69 72 20 7d 0a 65 6e 64 0a 0a 61 72 67 sedir }.end..arg
33b0: 73 20 3d 20 73 65 74 74 69 6e 67 73 2e 61 72 67 s = settings.arg
33c0: 73 2e 6d 61 70 20 7b 20 7c 61 72 67 7c 20 65 78 s.map { |arg| ex
33d0: 70 61 6e 64 28 61 72 67 2c 20 62 61 73 65 64 69 pand(arg, basedi
33e0: 72 29 20 7d 0a 0a 23 20 53 68 6f 77 20 74 68 65 r) }..# Show the
33f0: 20 68 6f 73 74 20 61 6e 64 20 62 61 73 65 20 64 host and base d
3400: 69 72 65 63 74 6f 72 79 3b 20 73 68 6f 77 20 74 irectory; show t
3410: 68 65 20 6c 6f 63 61 6c 20 46 6f 73 73 69 6c 27 he local Fossil'
3420: 73 20 66 69 6c 65 20 63 61 70 61 62 69 6c 69 74 s file capabilit
3430: 69 65 73 2e 0a 68 6f 73 74 20 3d 20 53 79 73 74 ies..host = Syst
3440: 65 6d 2e 68 6f 73 74 6e 61 6d 65 0a 70 75 74 73 em.hostname.puts
3450: 20 22 52 75 6e 6e 69 6e 67 20 6f 6e 20 23 7b 68 "Running on #{h
3460: 6f 73 74 7d 22 0a 70 75 74 73 20 22 52 75 6e 6e ost}".puts "Runn
3470: 69 6e 67 20 66 72 6f 6d 20 23 7b 62 61 73 65 64 ing from #{based
3480: 69 72 7d 22 0a 69 66 20 73 65 74 74 69 6e 67 73 ir}".if settings
3490: 2e 73 68 6f 77 5f 63 61 70 61 62 69 6c 69 74 69 .show_capabiliti
34a0: 65 73 0a 20 20 66 6f 75 6e 64 20 3d 20 50 72 6f es. found = Pro
34b0: 63 65 73 73 2e 66 69 6e 64 5f 65 78 65 63 75 74 cess.find_execut
34c0: 61 62 6c 65 28 22 66 6f 73 73 69 6c 22 29 0a 20 able("fossil").
34d0: 20 50 72 6f 63 65 73 73 2e 72 75 6e 28 22 67 65 Process.run("ge
34e0: 74 63 61 70 22 2c 20 5b 66 6f 75 6e 64 20 3f 20 tcap", [found ?
34f0: 46 69 6c 65 2e 72 65 61 6c 70 61 74 68 28 66 6f File.realpath(fo
3500: 75 6e 64 29 20 3a 20 22 22 5d 2c 20 6f 75 74 70 und) : ""], outp
3510: 75 74 3a 20 3a 69 6e 68 65 72 69 74 2c 20 65 72 ut: :inherit, er
3520: 72 6f 72 3a 20 3a 69 6e 68 65 72 69 74 29 0a 65 ror: :inherit).e
3530: 6e 64 0a 0a 23 20 57 68 65 72 65 20 74 68 69 73 nd..# Where this
3540: 20 68 6f 73 74 20 73 65 72 76 65 73 20 4f 43 58 host serves OCX
3550: 27 73 20 70 61 67 65 3a 20 6c 69 6e 6b 20 69 74 's page: link it
3560: 20 74 6f 20 74 68 65 20 6c 61 75 6e 63 68 65 72 to the launcher
3570: 20 6f 6e 6c 79 20 77 68 65 72 65 20 6e 6f 74 68 only where noth
3580: 69 6e 67 20 69 73 20 74 68 65 72 65 2c 0a 23 20 ing is there,.#
3590: 6c 65 61 76 69 6e 67 20 61 6e 20 65 78 69 73 74 leaving an exist
35a0: 69 6e 67 20 6c 69 6e 6b 20 61 6c 6f 6e 65 2c 20 ing link alone,
35b0: 73 6f 20 61 20 72 6f 6c 6c 62 61 63 6b 20 68 6f so a rollback ho
35c0: 6c 64 73 2e 0a 6c 61 75 6e 63 68 65 72 20 3d 20 lds..launcher =
35d0: 28 6c 6f 63 61 6c 2e 74 72 79 28 26 2e 6f 63 78 (local.try(&.ocx
35e0: 29 20 7c 7c 20 64 65 66 61 75 6c 74 2e 74 72 79 ) || default.try
35f0: 28 26 2e 6f 63 78 29 29 2e 74 72 79 28 26 2e 6c (&.ocx)).try(&.l
3600: 61 75 6e 63 68 65 72 29 0a 69 66 20 28 69 6e 64 auncher).if (ind
3610: 65 78 20 3d 20 61 72 67 73 2e 69 6e 64 65 78 28 ex = args.index(
3620: 22 2d 2d 65 78 74 72 6f 6f 74 22 29 29 20 26 26 "--extroot")) &&
3630: 20 6c 61 75 6e 63 68 65 72 20 26 26 20 46 69 6c launcher && Fil
3640: 65 2e 65 78 69 73 74 73 3f 28 6c 61 75 6e 63 68 e.exists?(launch
3650: 65 72 29 0a 20 20 6c 69 6e 6b 20 3d 20 46 69 6c er). link = Fil
3660: 65 2e 6a 6f 69 6e 28 61 72 67 73 5b 69 6e 64 65 e.join(args[inde
3670: 78 20 2b 20 31 5d 2c 20 22 6f 63 78 32 2d 63 67 x + 1], "ocx2-cg
3680: 69 22 29 0a 20 20 69 66 20 46 69 6c 65 2e 73 79 i"). if File.sy
3690: 6d 6c 69 6e 6b 3f 28 6c 69 6e 6b 29 20 7c 7c 20 mlink?(link) ||
36a0: 46 69 6c 65 2e 65 78 69 73 74 73 3f 28 6c 69 6e File.exists?(lin
36b0: 6b 29 0a 20 20 20 20 70 75 74 73 20 22 23 7b 6c k). puts "#{l
36c0: 69 6e 6b 7d 20 69 73 20 74 68 65 72 65 20 61 6c ink} is there al
36d0: 72 65 61 64 79 3b 20 6c 65 66 74 20 61 73 20 69 ready; left as i
36e0: 74 20 69 73 22 0a 20 20 65 6c 73 65 0a 20 20 20 t is". else.
36f0: 20 46 69 6c 65 2e 73 79 6d 6c 69 6e 6b 28 6c 61 File.symlink(la
3700: 75 6e 63 68 65 72 2c 20 6c 69 6e 6b 29 0a 20 20 uncher, link).
3710: 20 20 70 75 74 73 20 22 6c 69 6e 6b 65 64 20 23 puts "linked #
3720: 7b 6c 69 6e 6b 7d 20 74 6f 20 23 7b 6c 61 75 6e {link} to #{laun
3730: 63 68 65 72 7d 22 0a 20 20 65 6e 64 0a 65 6e 64 cher}". end.end
3740: 0a 0a 23 20 52 75 6e 20 46 6f 73 73 69 6c 20 61 ..# Run Fossil a
3750: 6e 64 20 72 65 74 75 72 6e 20 69 74 73 20 73 74 nd return its st
3760: 61 74 75 73 2e 0a 73 74 61 74 75 73 20 3d 20 50 atus..status = P
3770: 72 6f 63 65 73 73 2e 72 75 6e 28 65 78 70 61 6e rocess.run(expan
3780: 64 28 73 65 74 74 69 6e 67 73 2e 66 6f 73 73 69 d(settings.fossi
3790: 6c 2c 20 62 61 73 65 64 69 72 29 2c 20 61 72 67 l, basedir), arg
37a0: 73 2c 20 69 6e 70 75 74 3a 20 3a 69 6e 68 65 72 s, input: :inher
37b0: 69 74 2c 20 6f 75 74 70 75 74 3a 20 3a 69 6e 68 it, output: :inh
37c0: 65 72 69 74 2c 20 65 72 72 6f 72 3a 20 3a 69 6e erit, error: :in
37d0: 68 65 72 69 74 29 0a 65 78 69 74 20 73 74 61 74 herit).exit stat
37e0: 75 73 2e 65 78 69 74 5f 63 6f 64 65 3f 20 7c 7c us.exit_code? ||
37f0: 20 31 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 1..............
3800: 73 63 72 69 70 74 73 2d 66 6f 72 2d 72 65 76 69 scripts-for-revi
3810: 65 77 2d 33 2f 73 74 61 72 74 2d 6f 63 78 2e 63 ew-3/start-ocx.c
3820: 72 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r...............
3830: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3840: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3850: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3860: 00 00 00 00 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000
3870: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
3880: 30 30 31 36 35 32 36 00 31 35 32 37 30 36 36 34 0016526.15270664
3890: 36 31 33 00 30 31 35 37 36 34 00 20 30 00 00 00 613.015764. 0...
38a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
38b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
38c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
38d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
38e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
38f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3900: 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
3910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3920: 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
3930: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3940: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3950: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3960: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3970: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3990: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
39a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
39b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
39c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
39d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
39e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
39f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
3a00: 23 20 41 67 65 6e 74 73 3a 20 64 6f 20 6e 6f 74 # Agents: do not
3a10: 20 63 68 61 6e 67 65 20 74 68 69 73 20 66 69 6c change this fil
3a20: 65 20 6f 6e 20 61 6e 79 20 62 72 61 6e 63 68 20 e on any branch
3a30: 77 69 74 68 6f 75 74 20 74 68 65 20 6d 61 69 6e without the main
3a40: 74 61 69 6e 65 72 27 73 20 65 78 70 6c 69 63 69 tainer's explici
3a50: 74 20 61 70 70 72 6f 76 61 6c 20 6f 6e 20 74 68 t approval on th
3a60: 65 20 72 65 63 6f 72 64 2e 0a 23 20 46 6f 73 73 e record..# Foss
3a70: 69 6c 20 61 6e 64 20 73 79 73 74 65 6d 64 20 73 il and systemd s
3a80: 74 61 72 74 20 74 68 69 73 3b 20 73 65 74 74 69 tart this; setti
3a90: 6e 67 73 20 61 72 65 20 69 6e 20 74 68 65 20 73 ngs are in the s
3aa0: 65 72 76 65 72 73 2e 6a 73 6f 6e 20 62 65 73 69 ervers.json besi
3ab0: 64 65 20 74 68 69 73 20 70 72 6f 67 72 61 6d 2e de this program.
3ac0: 0a 23 20 42 75 69 6c 64 20 62 65 73 69 64 65 20 .# Build beside
3ad0: 72 65 63 65 69 70 74 73 20 77 69 74 68 20 73 68 receipts with sh
3ae0: 61 72 64 73 20 62 75 69 6c 64 20 73 74 61 72 74 ards build start
3af0: 2d 6f 63 78 20 72 65 63 65 69 70 74 73 2e 0a 72 -ocx receipts..r
3b00: 65 71 75 69 72 65 20 22 6a 73 6f 6e 22 0a 72 65 equire "json".re
3b10: 71 75 69 72 65 20 22 73 6f 63 6b 65 74 22 0a 0a quire "socket"..
3b20: 23 20 41 20 68 6f 73 74 20 74 68 61 74 20 6f 6e # A host that on
3b30: 6c 79 20 72 75 6e 73 20 74 68 65 20 64 61 65 6d ly runs the daem
3b40: 6f 6e 2c 20 73 75 63 68 20 61 73 20 61 20 62 75 on, such as a bu
3b50: 69 6c 64 20 6d 61 63 68 69 6e 65 2c 20 6c 65 61 ild machine, lea
3b60: 76 65 73 20 6f 75 74 20 74 68 65 0a 23 20 77 65 ves out the.# we
3b70: 62 20 70 61 67 65 27 73 20 61 6e 64 20 74 68 65 b page's and the
3b80: 20 72 65 63 65 69 70 74 20 73 65 72 76 69 63 65 receipt service
3b90: 27 73 20 73 65 74 74 69 6e 67 73 2e 0a 73 74 72 's settings..str
3ba0: 75 63 74 20 4f 43 58 0a 20 20 69 6e 63 6c 75 64 uct OCX. includ
3bb0: 65 20 4a 53 4f 4e 3a 3a 53 65 72 69 61 6c 69 7a e JSON::Serializ
3bc0: 61 62 6c 65 0a 20 20 67 65 74 74 65 72 20 72 65 able. getter re
3bd0: 70 6f 73 69 74 6f 72 69 65 73 20 3a 20 53 74 72 positories : Str
3be0: 69 6e 67 3f 0a 20 20 67 65 74 74 65 72 20 73 6f ing?. getter so
3bf0: 63 6b 65 74 5f 64 69 72 20 3a 20 53 74 72 69 6e cket_dir : Strin
3c00: 67 3f 0a 20 20 67 65 74 74 65 72 20 72 65 6c 65 g?. getter rele
3c10: 61 73 65 73 20 3a 20 53 74 72 69 6e 67 3f 0a 20 ases : String?.
3c20: 20 67 65 74 74 65 72 20 64 61 65 6d 6f 6e 5f 72 getter daemon_r
3c30: 6f 6f 74 20 3a 20 53 74 72 69 6e 67 3f 0a 20 20 oot : String?.
3c40: 67 65 74 74 65 72 20 68 6f 6d 65 73 20 3d 20 7b getter homes = {
3c50: 7d 20 6f 66 20 53 74 72 69 6e 67 20 3d 3e 20 53 } of String => S
3c60: 74 72 69 6e 67 20 23 20 72 65 61 64 2d 77 72 69 tring # read-wri
3c70: 74 65 2c 20 68 6f 73 74 20 70 61 74 68 20 3d 3e te, host path =>
3c80: 20 69 6e 73 69 64 65 20 74 68 65 20 64 61 65 6d inside the daem
3c90: 6f 6e 0a 20 20 67 65 74 74 65 72 20 74 6f 6f 6c on. getter tool
3ca0: 73 20 3d 20 7b 7d 20 6f 66 20 53 74 72 69 6e 67 s = {} of String
3cb0: 20 3d 3e 20 53 74 72 69 6e 67 20 23 20 72 65 61 => String # rea
3cc0: 64 2d 6f 6e 6c 79 2c 20 68 6f 73 74 20 70 61 74 d-only, host pat
3cd0: 68 20 3d 3e 20 69 6e 73 69 64 65 20 74 68 65 20 h => inside the
3ce0: 64 61 65 6d 6f 6e 0a 20 20 67 65 74 74 65 72 20 daemon. getter
3cf0: 72 65 61 64 5f 77 72 69 74 65 20 3d 20 5b 5d 20 read_write = []
3d00: 6f 66 20 53 74 72 69 6e 67 20 20 20 20 20 20 23 of String #
3d10: 20 6d 6f 72 65 20 72 65 61 64 2d 77 72 69 74 65 more read-write
3d20: 20 68 6f 73 74 20 70 61 74 68 73 2c 20 61 74 20 host paths, at
3d30: 74 68 65 20 73 61 6d 65 20 70 6c 61 63 65 0a 20 the same place.
3d40: 20 67 65 74 74 65 72 20 6c 61 75 6e 63 68 65 72 getter launcher
3d50: 20 3a 20 53 74 72 69 6e 67 3f 0a 65 6e 64 0a 0a : String?.end..
3d60: 73 74 72 75 63 74 20 53 65 72 76 65 72 0a 20 20 struct Server.
3d70: 69 6e 63 6c 75 64 65 20 4a 53 4f 4e 3a 3a 53 65 include JSON::Se
3d80: 72 69 61 6c 69 7a 61 62 6c 65 0a 20 20 67 65 74 rializable. get
3d90: 74 65 72 20 6f 63 78 20 3a 20 4f 43 58 3f 0a 65 ter ocx : OCX?.e
3da0: 6e 64 0a 0a 6c 69 62 20 4c 69 62 43 0a 20 20 66 nd..lib LibC. f
3db0: 75 6e 20 65 78 65 63 76 28 70 61 74 68 20 3a 20 un execv(path :
3dc0: 43 68 61 72 2a 2c 20 61 72 67 76 20 3a 20 43 68 Char*, argv : Ch
3dd0: 61 72 2a 2a 29 20 3a 20 49 6e 74 0a 65 6e 64 0a ar**) : Int.end.
3de0: 0a 62 65 67 69 6e 0a 20 20 23 20 43 68 6f 6f 73 .begin. # Choos
3df0: 65 20 74 68 65 20 6d 6f 64 65 3b 20 74 68 65 20 e the mode; the
3e00: 43 47 49 20 75 73 65 73 20 74 68 65 20 73 61 6d CGI uses the sam
3e10: 65 20 70 61 74 68 20 72 75 6c 65 20 61 73 20 74 e path rule as t
3e20: 68 65 20 77 65 62 20 70 61 67 65 2e 0a 20 20 6d he web page.. m
3e30: 6f 64 65 20 3d 20 46 69 6c 65 2e 62 61 73 65 6e ode = File.basen
3e40: 61 6d 65 28 50 52 4f 47 52 41 4d 5f 4e 41 4d 45 ame(PROGRAM_NAME
3e50: 29 20 3d 3d 20 22 6f 63 78 32 2d 63 67 69 22 20 ) == "ocx2-cgi"
3e60: 3f 20 22 63 67 69 22 20 3a 20 41 52 47 56 2e 66 ? "cgi" : ARGV.f
3e70: 69 72 73 74 3f 0a 20 20 61 62 6f 72 74 20 22 55 irst?. abort "U
3e80: 73 61 67 65 3a 20 73 74 61 72 74 2d 6f 63 78 20 sage: start-ocx
3e90: 72 65 63 65 69 70 74 73 7c 64 61 65 6d 6f 6e 3b receipts|daemon;
3ea0: 20 6f 63 78 32 2d 63 67 69 22 2c 20 32 20 75 6e ocx2-cgi", 2 un
3eb0: 6c 65 73 73 20 28 6d 6f 64 65 20 3d 3d 20 22 63 less (mode == "c
3ec0: 67 69 22 20 26 26 20 41 52 47 56 2e 65 6d 70 74 gi" && ARGV.empt
3ed0: 79 3f 29 20 7c 7c 20 28 41 52 47 56 2e 73 69 7a y?) || (ARGV.siz
3ee0: 65 20 3d 3d 20 31 20 26 26 20 7b 22 72 65 63 65 e == 1 && {"rece
3ef0: 69 70 74 73 22 2c 20 22 64 61 65 6d 6f 6e 22 7d ipts", "daemon"}
3f00: 2e 69 6e 63 6c 75 64 65 73 3f 28 6d 6f 64 65 29 .includes?(mode)
3f10: 29 0a 20 20 66 69 6c 65 20 3d 20 46 69 6c 65 2e ). file = File.
3f20: 6a 6f 69 6e 28 46 69 6c 65 2e 64 69 72 6e 61 6d join(File.dirnam
3f30: 65 28 50 72 6f 63 65 73 73 2e 65 78 65 63 75 74 e(Process.execut
3f40: 61 62 6c 65 5f 70 61 74 68 2e 6e 6f 74 5f 6e 69 able_path.not_ni
3f50: 6c 21 29 2c 20 22 73 65 72 76 65 72 73 2e 6a 73 l!), "servers.js
3f60: 6f 6e 22 29 0a 20 20 62 65 67 69 6e 0a 20 20 20 on"). begin.
3f70: 20 73 65 72 76 65 72 73 20 3d 20 46 69 6c 65 2e servers = File.
3f80: 6f 70 65 6e 28 66 69 6c 65 29 20 64 6f 20 7c 69 open(file) do |i
3f90: 6e 70 75 74 7c 0a 20 20 20 20 20 20 69 6e 66 6f nput|. info
3fa0: 20 3d 20 69 6e 70 75 74 2e 69 6e 66 6f 0a 20 20 = input.info.
3fb0: 20 20 20 20 61 62 6f 72 74 20 22 23 7b 66 69 6c abort "#{fil
3fc0: 65 7d 3a 20 6d 75 73 74 20 62 65 20 6f 77 6e 65 e}: must be owne
3fd0: 64 20 62 79 20 72 6f 6f 74 20 61 6e 64 20 6e 6f d by root and no
3fe0: 74 20 77 72 69 74 61 62 6c 65 20 62 79 20 67 72 t writable by gr
3ff0: 6f 75 70 20 6f 72 20 6f 74 68 65 72 73 22 2c 20 oup or others",
4000: 32 20 75 6e 6c 65 73 73 20 69 6e 66 6f 2e 6f 77 2 unless info.ow
4010: 6e 65 72 5f 69 64 20 3d 3d 20 22 30 22 20 26 26 ner_id == "0" &&
4020: 20 69 6e 66 6f 2e 70 65 72 6d 69 73 73 69 6f 6e info.permission
4030: 73 2e 76 61 6c 75 65 20 26 20 30 6f 30 32 32 20 s.value & 0o022
4040: 3d 3d 20 30 0a 20 20 20 20 20 20 48 61 73 68 28 == 0. Hash(
4050: 53 74 72 69 6e 67 2c 20 4a 53 4f 4e 3a 3a 41 6e String, JSON::An
4060: 79 29 2e 66 72 6f 6d 5f 6a 73 6f 6e 28 69 6e 70 y).from_json(inp
4070: 75 74 29 0a 20 20 20 20 65 6e 64 0a 20 20 20 20 ut). end.
4080: 6c 6f 63 61 6c 20 3d 20 73 65 72 76 65 72 73 5b local = servers[
4090: 53 79 73 74 65 6d 2e 68 6f 73 74 6e 61 6d 65 5d System.hostname]
40a0: 3f 2e 74 72 79 20 7b 20 7c 65 6e 74 72 79 7c 20 ?.try { |entry|
40b0: 53 65 72 76 65 72 2e 66 72 6f 6d 5f 6a 73 6f 6e Server.from_json
40c0: 28 65 6e 74 72 79 2e 74 6f 5f 6a 73 6f 6e 29 20 (entry.to_json)
40d0: 7d 0a 20 20 20 20 64 65 66 61 75 6c 74 20 3d 20 }. default =
40e0: 73 65 72 76 65 72 73 5b 22 2a 22 5d 3f 2e 74 72 servers["*"]?.tr
40f0: 79 20 7b 20 7c 65 6e 74 72 79 7c 20 53 65 72 76 y { |entry| Serv
4100: 65 72 2e 66 72 6f 6d 5f 6a 73 6f 6e 28 65 6e 74 er.from_json(ent
4110: 72 79 2e 74 6f 5f 6a 73 6f 6e 29 20 7d 0a 20 20 ry.to_json) }.
4120: 20 20 73 65 74 74 69 6e 67 73 20 3d 20 6c 6f 63 settings = loc
4130: 61 6c 2e 74 72 79 28 26 2e 6f 63 78 29 20 7c 7c al.try(&.ocx) ||
4140: 20 64 65 66 61 75 6c 74 2e 74 72 79 28 26 2e 6f default.try(&.o
4150: 63 78 29 20 7c 7c 20 61 62 6f 72 74 20 22 23 7b cx) || abort "#{
4160: 66 69 6c 65 7d 3a 20 6d 69 73 73 69 6e 67 20 6f file}: missing o
4170: 63 78 22 2c 20 32 0a 20 20 72 65 73 63 75 65 20 cx", 2. rescue
4180: 65 78 20 3a 20 49 4f 3a 3a 45 72 72 6f 72 20 7c ex : IO::Error |
4190: 20 4a 53 4f 4e 3a 3a 50 61 72 73 65 45 78 63 65 JSON::ParseExce
41a0: 70 74 69 6f 6e 0a 20 20 20 20 61 62 6f 72 74 20 ption. abort
41b0: 22 23 7b 66 69 6c 65 7d 3a 20 63 61 6e 6e 6f 74 "#{file}: cannot
41c0: 20 72 65 61 64 20 6f 63 78 3a 20 23 7b 65 78 2e read ocx: #{ex.
41d0: 6d 65 73 73 61 67 65 2e 74 6f 5f 73 2e 6c 69 6e message.to_s.lin
41e0: 65 73 2e 66 69 72 73 74 7d 22 2c 20 32 0a 20 20 es.first}", 2.
41f0: 65 6e 64 0a 20 20 6d 69 73 73 69 6e 67 20 3d 20 end. missing =
4200: 2d 3e 28 6e 61 6d 65 20 3a 20 53 74 72 69 6e 67 ->(name : String
4210: 29 20 7b 20 61 62 6f 72 74 20 22 23 7b 66 69 6c ) { abort "#{fil
4220: 65 7d 3a 20 6f 63 78 20 68 61 73 20 6e 6f 20 23 e}: ocx has no #
4230: 7b 6e 61 6d 65 7d 20 66 6f 72 20 23 7b 6d 6f 64 {name} for #{mod
4240: 65 7d 22 2c 20 32 20 7d 0a 20 20 63 61 73 65 20 e}", 2 }. case
4250: 6d 6f 64 65 0a 20 20 77 68 65 6e 20 22 63 67 69 mode. when "cgi
4260: 22 0a 20 20 20 20 72 65 6c 65 61 73 65 73 2c 20 ". releases,
4270: 73 6f 63 6b 65 74 5f 64 69 72 20 3d 20 73 65 74 socket_dir = set
4280: 74 69 6e 67 73 2e 72 65 6c 65 61 73 65 73 20 7c tings.releases |
4290: 7c 20 6d 69 73 73 69 6e 67 2e 63 61 6c 6c 28 22 | missing.call("
42a0: 72 65 6c 65 61 73 65 73 22 29 2c 20 73 65 74 74 releases"), sett
42b0: 69 6e 67 73 2e 73 6f 63 6b 65 74 5f 64 69 72 20 ings.socket_dir
42c0: 7c 7c 20 6d 69 73 73 69 6e 67 2e 63 61 6c 6c 28 || missing.call(
42d0: 22 73 6f 63 6b 65 74 5f 64 69 72 22 29 0a 20 20 "socket_dir").
42e0: 20 20 72 65 6c 65 61 73 65 20 3d 20 46 69 6c 65 release = File
42f0: 2e 72 65 61 6c 70 61 74 68 28 46 69 6c 65 2e 6a .realpath(File.j
4300: 6f 69 6e 28 72 65 6c 65 61 73 65 73 2c 20 22 63 oin(releases, "c
4310: 75 72 72 65 6e 74 22 29 29 0a 20 20 20 20 77 6f urrent")). wo
4320: 72 64 73 20 3d 20 28 45 4e 56 5b 22 50 41 54 48 rds = (ENV["PATH
4330: 5f 49 4e 46 4f 22 5d 3f 20 7c 7c 20 22 22 29 2e _INFO"]? || "").
4340: 73 70 6c 69 74 28 27 2f 27 29 2e 72 65 6a 65 63 split('/').rejec
4350: 74 28 26 2e 65 6d 70 74 79 3f 29 0a 20 20 20 20 t(&.empty?).
4360: 6e 61 6d 65 20 3d 20 77 6f 72 64 73 5b 28 28 77 name = words[((w
4370: 6f 72 64 73 2e 72 69 6e 64 65 78 28 22 6f 63 78 ords.rindex("ocx
4380: 32 2d 63 67 69 22 29 20 7c 7c 20 2d 31 29 20 2b 2-cgi") || -1) +
4390: 20 31 29 2e 2e 5d 2e 66 69 72 73 74 3f 0a 20 20 1)..].first?.
43a0: 20 20 75 6e 6c 65 73 73 20 6e 61 6d 65 20 3d 3d unless name ==
43b0: 20 22 72 65 63 65 69 70 74 22 0a 20 20 20 20 20 "receipt".
43c0: 20 23 20 54 65 6d 70 6f 72 61 72 79 20 70 61 73 # Temporary pas
43d0: 73 74 68 72 6f 75 67 68 20 75 6e 74 69 6c 20 74 sthrough until t
43e0: 68 65 20 6f 74 68 65 72 20 43 47 49 20 74 6f 6f he other CGI too
43f0: 6c 73 20 74 61 6c 6b 20 74 6f 20 74 68 65 20 64 ls talk to the d
4400: 61 65 6d 6f 6e 2e 0a 20 20 20 20 20 20 61 72 67 aemon.. arg
4410: 76 20 3d 20 5b 46 69 6c 65 2e 6a 6f 69 6e 28 72 v = [File.join(r
4420: 65 6c 65 61 73 65 2c 20 22 6f 63 78 32 2d 63 67 elease, "ocx2-cg
4430: 69 22 29 2e 74 6f 5f 75 6e 73 61 66 65 2c 20 50 i").to_unsafe, P
4440: 6f 69 6e 74 65 72 28 55 49 6e 74 38 29 2e 6e 75 ointer(UInt8).nu
4450: 6c 6c 5d 0a 20 20 20 20 20 20 4c 69 62 43 2e 65 ll]. LibC.e
4460: 78 65 63 76 28 46 69 6c 65 2e 6a 6f 69 6e 28 72 xecv(File.join(r
4470: 65 6c 65 61 73 65 2c 20 22 6f 63 78 32 22 29 2c elease, "ocx2"),
4480: 20 61 72 67 76 2e 74 6f 5f 75 6e 73 61 66 65 29 argv.to_unsafe)
4490: 0a 20 20 20 20 20 20 72 61 69 73 65 20 49 4f 3a . raise IO:
44a0: 3a 45 72 72 6f 72 2e 66 72 6f 6d 5f 65 72 72 6e :Error.from_errn
44b0: 6f 28 22 65 78 65 63 76 22 29 0a 20 20 20 20 65 o("execv"). e
44c0: 6e 64 0a 20 20 20 20 23 20 43 6f 6e 6e 65 63 74 nd. # Connect
44d0: 20 61 6e 64 20 77 72 69 74 65 20 46 6f 73 73 69 and write Fossi
44e0: 6c 27 73 20 69 64 65 6e 74 69 74 79 20 62 65 66 l's identity bef
44f0: 6f 72 65 20 63 6c 6f 73 69 6e 67 20 72 75 6e 74 ore closing runt
4500: 69 6d 65 20 64 65 73 63 72 69 70 74 6f 72 73 2e ime descriptors.
4510: 0a 20 20 20 20 72 65 70 6f 73 69 74 6f 72 79 20 . repository
4520: 3d 20 46 69 6c 65 2e 62 61 73 65 6e 61 6d 65 28 = File.basename(
4530: 45 4e 56 5b 22 46 4f 53 53 49 4c 5f 52 45 50 4f ENV["FOSSIL_REPO
4540: 53 49 54 4f 52 59 22 5d 3f 20 7c 7c 20 22 22 2c SITORY"]? || "",
4550: 20 22 2e 66 6f 73 73 69 6c 22 29 0a 20 20 20 20 ".fossil").
4560: 62 65 67 69 6e 0a 20 20 20 20 20 20 73 6f 63 6b begin. sock
4570: 65 74 20 3d 20 53 6f 63 6b 65 74 2e 6e 65 77 28 et = Socket.new(
4580: 3a 75 6e 69 78 2c 20 3a 73 74 72 65 61 6d 29 0a :unix, :stream).
4590: 20 20 20 20 20 20 73 6f 63 6b 65 74 2e 63 6f 6e socket.con
45a0: 6e 65 63 74 28 53 6f 63 6b 65 74 3a 3a 55 4e 49 nect(Socket::UNI
45b0: 58 41 64 64 72 65 73 73 2e 6e 65 77 28 46 69 6c XAddress.new(Fil
45c0: 65 2e 6a 6f 69 6e 28 73 6f 63 6b 65 74 5f 64 69 e.join(socket_di
45d0: 72 2c 20 22 72 65 63 65 69 70 74 73 2e 73 6f 63 r, "receipts.soc
45e0: 6b 22 29 29 2c 20 32 2e 73 65 63 6f 6e 64 73 29 k")), 2.seconds)
45f0: 0a 20 20 20 20 20 20 73 6f 63 6b 65 74 2e 77 72 . socket.wr
4600: 69 74 65 5f 74 69 6d 65 6f 75 74 20 3d 20 32 2e ite_timeout = 2.
4610: 73 65 63 6f 6e 64 73 0a 20 20 20 20 20 20 73 6f seconds. so
4620: 63 6b 65 74 2e 70 75 74 73 28 7b 75 73 65 72 3a cket.puts({user:
4630: 20 45 4e 56 5b 22 46 4f 53 53 49 4c 5f 55 53 45 ENV["FOSSIL_USE
4640: 52 22 5d 3f 2c 20 63 61 70 61 62 69 6c 69 74 69 R"]?, capabiliti
4650: 65 73 3a 20 45 4e 56 5b 22 46 4f 53 53 49 4c 5f es: ENV["FOSSIL_
4660: 43 41 50 41 42 49 4c 49 54 49 45 53 22 5d 3f 20 CAPABILITIES"]?
4670: 7c 7c 20 22 22 2c 20 72 65 70 6f 73 69 74 6f 72 || "", repositor
4680: 79 3a 20 72 65 70 6f 73 69 74 6f 72 79 7d 2e 74 y: repository}.t
4690: 6f 5f 6a 73 6f 6e 29 0a 20 20 20 20 20 20 73 6f o_json). so
46a0: 63 6b 65 74 2e 66 6c 75 73 68 0a 20 20 20 20 72 cket.flush. r
46b0: 65 73 63 75 65 20 53 6f 63 6b 65 74 3a 3a 45 72 escue Socket::Er
46c0: 72 6f 72 20 7c 20 49 4f 3a 3a 45 72 72 6f 72 0a ror | IO::Error.
46d0: 20 20 20 20 20 20 70 75 74 73 20 22 53 74 61 74 puts "Stat
46e0: 75 73 3a 20 35 30 33 5c 72 5c 6e 43 6f 6e 74 65 us: 503\r\nConte
46f0: 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c 69 63 61 nt-Type: applica
4700: 74 69 6f 6e 2f 6a 73 6f 6e 5c 72 5c 6e 5c 72 5c tion/json\r\n\r\
4710: 6e 7b 5c 22 75 6e 61 76 61 69 6c 61 62 6c 65 5c n{\"unavailable\
4720: 22 3a 5c 22 72 65 63 65 69 70 74 20 73 65 72 76 ":\"receipt serv
4730: 69 63 65 20 6e 6f 74 20 61 6e 73 77 65 72 69 6e ice not answerin
4740: 67 5c 22 7d 22 0a 20 20 20 20 20 20 65 78 69 74 g\"}". exit
4750: 20 30 0a 20 20 20 20 65 6e 64 0a 20 20 20 20 23 0. end. #
4760: 20 42 75 69 6c 64 20 74 68 65 20 72 65 63 65 69 Build the recei
4770: 70 74 20 43 47 49 27 73 20 73 61 6e 64 62 6f 78 pt CGI's sandbox
4780: 20 77 69 74 68 20 6f 6e 6c 79 20 74 68 65 20 72 with only the r
4790: 65 71 75 65 73 74 20 66 69 65 6c 64 73 20 69 74 equest fields it
47a0: 20 6e 65 65 64 73 2e 0a 20 20 20 20 61 72 67 73 needs.. args
47b0: 20 3d 20 25 77 28 2d 2d 75 6e 73 68 61 72 65 2d = %w(--unshare-
47c0: 61 6c 6c 20 2d 2d 64 69 65 2d 77 69 74 68 2d 70 all --die-with-p
47d0: 61 72 65 6e 74 20 2d 2d 6e 65 77 2d 73 65 73 73 arent --new-sess
47e0: 69 6f 6e 20 2d 2d 63 61 70 2d 64 72 6f 70 20 41 ion --cap-drop A
47f0: 4c 4c 20 2d 2d 63 6c 65 61 72 65 6e 76 20 2d 2d LL --clearenv --
4800: 72 6f 2d 62 69 6e 64 20 2f 75 73 72 20 2f 75 73 ro-bind /usr /us
4810: 72 29 0a 20 20 20 20 25 77 28 2f 6c 69 62 20 2f r). %w(/lib /
4820: 6c 69 62 36 34 20 2f 62 69 6e 20 2f 65 74 63 2f lib64 /bin /etc/
4830: 70 61 73 73 77 64 29 2e 65 61 63 68 20 7b 20 7c passwd).each { |
4840: 70 61 74 68 7c 20 61 72 67 73 2e 63 6f 6e 63 61 path| args.conca
4850: 74 28 5b 22 2d 2d 72 6f 2d 62 69 6e 64 22 2c 20 t(["--ro-bind",
4860: 70 61 74 68 2c 20 70 61 74 68 5d 29 20 69 66 20 path, path]) if
4870: 46 69 6c 65 2e 65 78 69 73 74 73 3f 28 70 61 74 File.exists?(pat
4880: 68 29 20 7d 0a 20 20 20 20 61 72 67 73 2e 63 6f h) }. args.co
4890: 6e 63 61 74 28 5b 22 2d 2d 70 72 6f 63 22 2c 20 ncat(["--proc",
48a0: 22 2f 70 72 6f 63 22 2c 20 22 2d 2d 64 65 76 22 "/proc", "--dev"
48b0: 2c 20 22 2f 64 65 76 22 2c 20 22 2d 2d 74 6d 70 , "/dev", "--tmp
48c0: 66 73 22 2c 20 22 2f 74 6d 70 22 2c 20 22 2d 2d fs", "/tmp", "--
48d0: 72 6f 2d 62 69 6e 64 22 2c 20 46 69 6c 65 2e 6a ro-bind", File.j
48e0: 6f 69 6e 28 72 65 6c 65 61 73 65 2c 20 22 6f 63 oin(release, "oc
48f0: 78 32 22 29 2c 20 22 2f 72 65 6c 65 61 73 65 2f x2"), "/release/
4900: 6f 63 78 32 2d 63 67 69 22 5d 29 0a 20 20 20 20 ocx2-cgi"]).
4910: 25 77 28 52 45 51 55 45 53 54 5f 4d 45 54 48 4f %w(REQUEST_METHO
4920: 44 20 51 55 45 52 59 5f 53 54 52 49 4e 47 20 50 D QUERY_STRING P
4930: 41 54 48 5f 49 4e 46 4f 20 43 4f 4e 54 45 4e 54 ATH_INFO CONTENT
4940: 5f 4c 45 4e 47 54 48 20 43 4f 4e 54 45 4e 54 5f _LENGTH CONTENT_
4950: 54 59 50 45 20 48 54 54 50 53 20 48 54 54 50 5f TYPE HTTPS HTTP_
4960: 48 4f 53 54 20 48 54 54 50 5f 52 45 46 45 52 45 HOST HTTP_REFERE
4970: 52 20 46 4f 53 53 49 4c 5f 55 53 45 52 20 46 4f R FOSSIL_USER FO
4980: 53 53 49 4c 5f 43 41 50 41 42 49 4c 49 54 49 45 SSIL_CAPABILITIE
4990: 53 20 46 4f 53 53 49 4c 5f 55 52 49 29 2e 65 61 S FOSSIL_URI).ea
49a0: 63 68 20 64 6f 20 7c 6b 65 79 7c 0a 20 20 20 20 ch do |key|.
49b0: 20 20 61 72 67 73 2e 63 6f 6e 63 61 74 28 5b 22 args.concat(["
49c0: 2d 2d 73 65 74 65 6e 76 22 2c 20 6b 65 79 2c 20 --setenv", key,
49d0: 45 4e 56 5b 6b 65 79 5d 5d 29 20 69 66 20 45 4e ENV[key]]) if EN
49e0: 56 2e 68 61 73 5f 6b 65 79 3f 28 6b 65 79 29 0a V.has_key?(key).
49f0: 20 20 20 20 65 6e 64 0a 20 20 20 20 61 72 67 73 end. args
4a00: 2e 63 6f 6e 63 61 74 28 5b 22 2d 2d 73 65 74 65 .concat(["--sete
4a10: 6e 76 22 2c 20 22 46 4f 53 53 49 4c 5f 52 45 50 nv", "FOSSIL_REP
4a20: 4f 53 49 54 4f 52 59 22 2c 20 72 65 70 6f 73 69 OSITORY", reposi
4a30: 74 6f 72 79 2c 20 22 2d 2d 73 65 74 65 6e 76 22 tory, "--setenv"
4a40: 2c 20 22 50 41 54 48 22 2c 20 22 2f 75 73 72 2f , "PATH", "/usr/
4a50: 62 69 6e 22 2c 20 22 2f 72 65 6c 65 61 73 65 2f bin", "/release/
4a60: 6f 63 78 32 2d 63 67 69 22 2c 20 22 2d 2d 72 65 ocx2-cgi", "--re
4a70: 63 65 69 70 74 2d 66 64 22 2c 20 22 33 22 5d 29 ceipt-fd", "3"])
4a80: 0a 20 20 20 20 23 20 4b 65 65 70 20 6f 6e 6c 79 . # Keep only
4a90: 20 74 68 65 20 73 6f 63 6b 65 74 20 61 62 6f 76 the socket abov
4aa0: 65 20 73 74 64 65 72 72 2c 20 61 74 20 64 65 73 e stderr, at des
4ab0: 63 72 69 70 74 6f 72 20 33 2c 20 74 68 72 6f 75 criptor 3, throu
4ac0: 67 68 20 65 78 65 63 2e 0a 20 20 20 20 64 65 73 gh exec.. des
4ad0: 63 72 69 70 74 6f 72 73 20 3d 20 44 69 72 2e 63 criptors = Dir.c
4ae0: 68 69 6c 64 72 65 6e 28 22 2f 70 72 6f 63 2f 73 hildren("/proc/s
4af0: 65 6c 66 2f 66 64 22 29 2e 6d 61 70 28 26 2e 74 elf/fd").map(&.t
4b00: 6f 5f 69 29 0a 20 20 20 20 64 65 73 63 72 69 70 o_i). descrip
4b10: 74 6f 72 73 2e 65 61 63 68 20 7b 20 7c 66 64 7c tors.each { |fd|
4b20: 20 4c 69 62 43 2e 63 6c 6f 73 65 28 66 64 29 20 LibC.close(fd)
4b30: 69 66 20 66 64 20 3e 20 32 20 26 26 20 66 64 20 if fd > 2 && fd
4b40: 21 3d 20 73 6f 63 6b 65 74 2e 66 64 20 7d 0a 20 != socket.fd }.
4b50: 20 20 20 72 61 69 73 65 20 49 4f 3a 3a 45 72 72 raise IO::Err
4b60: 6f 72 2e 66 72 6f 6d 5f 65 72 72 6e 6f 28 22 64 or.from_errno("d
4b70: 75 70 32 22 29 20 69 66 20 4c 69 62 43 2e 64 75 up2") if LibC.du
4b80: 70 32 28 73 6f 63 6b 65 74 2e 66 64 2c 20 33 29 p2(socket.fd, 3)
4b90: 20 3d 3d 20 2d 31 0a 20 20 20 20 4c 69 62 43 2e == -1. LibC.
4ba0: 63 6c 6f 73 65 28 73 6f 63 6b 65 74 2e 66 64 29 close(socket.fd)
4bb0: 20 75 6e 6c 65 73 73 20 73 6f 63 6b 65 74 2e 66 unless socket.f
4bc0: 64 20 3d 3d 20 33 0a 20 20 20 20 72 61 69 73 65 d == 3. raise
4bd0: 20 49 4f 3a 3a 45 72 72 6f 72 2e 66 72 6f 6d 5f IO::Error.from_
4be0: 65 72 72 6e 6f 28 22 66 63 6e 74 6c 22 29 20 69 errno("fcntl") i
4bf0: 66 20 4c 69 62 43 2e 66 63 6e 74 6c 28 33 2c 20 f LibC.fcntl(3,
4c00: 4c 69 62 43 3a 3a 46 5f 53 45 54 46 44 2c 20 30 LibC::F_SETFD, 0
4c10: 29 20 3d 3d 20 2d 31 0a 20 20 77 68 65 6e 20 22 ) == -1. when "
4c20: 72 65 63 65 69 70 74 73 22 0a 20 20 20 20 23 20 receipts". #
4c30: 47 69 76 65 20 74 68 65 20 73 65 72 76 69 63 65 Give the service
4c40: 20 6f 6e 6c 79 20 74 68 65 20 72 65 70 6f 73 69 only the reposi
4c50: 74 6f 72 79 20 64 69 72 65 63 74 6f 72 79 20 61 tory directory a
4c60: 6e 64 20 69 74 73 20 73 6f 63 6b 65 74 20 64 69 nd its socket di
4c70: 72 65 63 74 6f 72 79 2e 0a 20 20 20 20 72 65 70 rectory.. rep
4c80: 6f 73 69 74 6f 72 69 65 73 2c 20 73 6f 63 6b 65 ositories, socke
4c90: 74 5f 64 69 72 20 3d 20 73 65 74 74 69 6e 67 73 t_dir = settings
4ca0: 2e 72 65 70 6f 73 69 74 6f 72 69 65 73 20 7c 7c .repositories ||
4cb0: 20 6d 69 73 73 69 6e 67 2e 63 61 6c 6c 28 22 72 missing.call("r
4cc0: 65 70 6f 73 69 74 6f 72 69 65 73 22 29 2c 20 73 epositories"), s
4cd0: 65 74 74 69 6e 67 73 2e 73 6f 63 6b 65 74 5f 64 ettings.socket_d
4ce0: 69 72 20 7c 7c 20 6d 69 73 73 69 6e 67 2e 63 61 ir || missing.ca
4cf0: 6c 6c 28 22 73 6f 63 6b 65 74 5f 64 69 72 22 29 ll("socket_dir")
4d00: 0a 20 20 20 20 65 78 65 63 75 74 61 62 6c 65 20 . executable
4d10: 3d 20 50 72 6f 63 65 73 73 2e 65 78 65 63 75 74 = Process.execut
4d20: 61 62 6c 65 5f 70 61 74 68 20 7c 7c 20 72 61 69 able_path || rai
4d30: 73 65 20 49 4f 3a 3a 45 72 72 6f 72 2e 6e 65 77 se IO::Error.new
4d40: 28 22 63 61 6e 6e 6f 74 20 6c 6f 63 61 74 65 20 ("cannot locate
4d50: 65 78 65 63 75 74 61 62 6c 65 22 29 0a 20 20 20 executable").
4d60: 20 61 72 67 73 20 3d 20 25 77 28 2d 2d 75 6e 73 args = %w(--uns
4d70: 68 61 72 65 2d 61 6c 6c 20 2d 2d 64 69 65 2d 77 hare-all --die-w
4d80: 69 74 68 2d 70 61 72 65 6e 74 20 2d 2d 6e 65 77 ith-parent --new
4d90: 2d 73 65 73 73 69 6f 6e 20 2d 2d 63 61 70 2d 64 -session --cap-d
4da0: 72 6f 70 20 41 4c 4c 20 2d 2d 63 6c 65 61 72 65 rop ALL --cleare
4db0: 6e 76 20 2d 2d 72 6f 2d 62 69 6e 64 20 2f 75 73 nv --ro-bind /us
4dc0: 72 20 2f 75 73 72 29 0a 20 20 20 20 25 77 28 2f r /usr). %w(/
4dd0: 6c 69 62 20 2f 6c 69 62 36 34 29 2e 65 61 63 68 lib /lib64).each
4de0: 20 7b 20 7c 70 61 74 68 7c 20 61 72 67 73 2e 63 { |path| args.c
4df0: 6f 6e 63 61 74 28 5b 22 2d 2d 72 6f 2d 62 69 6e oncat(["--ro-bin
4e00: 64 22 2c 20 70 61 74 68 2c 20 70 61 74 68 5d 29 d", path, path])
4e10: 20 69 66 20 46 69 6c 65 2e 65 78 69 73 74 73 3f if File.exists?
4e20: 28 70 61 74 68 29 20 7d 0a 20 20 20 20 61 72 67 (path) }. arg
4e30: 73 2e 63 6f 6e 63 61 74 28 5b 22 2d 2d 64 65 76 s.concat(["--dev
4e40: 22 2c 20 22 2f 64 65 76 22 2c 20 22 2d 2d 74 6d ", "/dev", "--tm
4e50: 70 66 73 22 2c 20 22 2f 74 6d 70 22 2c 20 22 2d pfs", "/tmp", "-
4e60: 2d 72 6f 2d 62 69 6e 64 22 2c 20 72 65 70 6f 73 -ro-bind", repos
4e70: 69 74 6f 72 69 65 73 2c 20 22 2f 72 65 70 6f 73 itories, "/repos
4e80: 69 74 6f 72 69 65 73 22 2c 20 22 2d 2d 62 69 6e itories", "--bin
4e90: 64 22 2c 20 73 6f 63 6b 65 74 5f 64 69 72 2c 20 d", socket_dir,
4ea0: 22 2f 72 75 6e 2f 6f 63 78 22 2c 0a 20 20 20 20 "/run/ocx",.
4eb0: 20 20 20 20 20 20 20 20 20 20 20 20 20 22 2d 2d "--
4ec0: 72 6f 2d 62 69 6e 64 22 2c 20 46 69 6c 65 2e 6a ro-bind", File.j
4ed0: 6f 69 6e 28 46 69 6c 65 2e 64 69 72 6e 61 6d 65 oin(File.dirname
4ee0: 28 65 78 65 63 75 74 61 62 6c 65 29 2c 20 22 72 (executable), "r
4ef0: 65 63 65 69 70 74 73 22 29 2c 20 22 2f 72 65 63 eceipts"), "/rec
4f00: 65 69 70 74 73 22 2c 20 22 2f 72 65 63 65 69 70 eipts", "/receip
4f10: 74 73 22 5d 29 0a 20 20 77 68 65 6e 20 22 64 61 ts"]). when "da
4f20: 65 6d 6f 6e 22 0a 20 20 20 20 23 20 53 68 61 72 emon". # Shar
4f30: 65 20 70 72 6f 63 65 73 73 65 73 20 61 6e 64 20 e processes and
4f40: 6e 65 74 77 6f 72 6b 20 73 6f 20 77 61 74 63 68 network so watch
4f50: 65 72 73 20 63 61 6e 20 6f 75 74 6c 69 76 65 20 ers can outlive
4f60: 61 20 64 61 65 6d 6f 6e 20 72 65 73 74 61 72 74 a daemon restart
4f70: 2e 0a 20 20 20 20 72 6f 6f 74 20 3d 20 73 65 74 .. root = set
4f80: 74 69 6e 67 73 2e 64 61 65 6d 6f 6e 5f 72 6f 6f tings.daemon_roo
4f90: 74 20 7c 7c 20 6d 69 73 73 69 6e 67 2e 63 61 6c t || missing.cal
4fa0: 6c 28 22 64 61 65 6d 6f 6e 5f 72 6f 6f 74 22 29 l("daemon_root")
4fb0: 0a 20 20 20 20 61 72 67 73 20 3d 20 25 77 28 2d . args = %w(-
4fc0: 2d 75 6e 73 68 61 72 65 2d 75 73 65 72 20 2d 2d -unshare-user --
4fd0: 75 6e 73 68 61 72 65 2d 69 70 63 20 2d 2d 75 6e unshare-ipc --un
4fe0: 73 68 61 72 65 2d 75 74 73 20 2d 2d 63 6c 65 61 share-uts --clea
4ff0: 72 65 6e 76 20 2d 2d 73 65 74 65 6e 76 20 48 4f renv --setenv HO
5000: 4d 45 20 2f 72 6f 6f 74 20 2d 2d 73 65 74 65 6e ME /root --seten
5010: 76 20 50 41 54 48 20 2f 75 73 72 2f 62 69 6e 3a v PATH /usr/bin:
5020: 2f 62 69 6e 20 2d 2d 72 6f 2d 62 69 6e 64 20 2f /bin --ro-bind /
5030: 75 73 72 20 2f 75 73 72 29 0a 20 20 20 20 25 77 usr /usr). %w
5040: 28 2f 6c 69 62 20 2f 6c 69 62 36 34 20 2f 62 69 (/lib /lib64 /bi
5050: 6e 20 2f 73 62 69 6e 20 2f 65 74 63 2f 73 73 6c n /sbin /etc/ssl
5060: 20 2f 65 74 63 2f 70 6b 69 20 2f 65 74 63 2f 72 /etc/pki /etc/r
5070: 65 73 6f 6c 76 2e 63 6f 6e 66 20 2f 65 74 63 2f esolv.conf /etc/
5080: 68 6f 73 74 73 20 2f 65 74 63 2f 6e 73 73 77 69 hosts /etc/nsswi
5090: 74 63 68 2e 63 6f 6e 66 20 2f 65 74 63 2f 70 61 tch.conf /etc/pa
50a0: 73 73 77 64 20 2f 65 74 63 2f 67 72 6f 75 70 29 sswd /etc/group)
50b0: 2e 65 61 63 68 20 64 6f 20 7c 70 61 74 68 7c 0a .each do |path|.
50c0: 20 20 20 20 20 20 61 72 67 73 2e 63 6f 6e 63 61 args.conca
50d0: 74 28 5b 22 2d 2d 72 6f 2d 62 69 6e 64 22 2c 20 t(["--ro-bind",
50e0: 70 61 74 68 2c 20 70 61 74 68 5d 29 20 69 66 20 path, path]) if
50f0: 46 69 6c 65 2e 65 78 69 73 74 73 3f 28 70 61 74 File.exists?(pat
5100: 68 29 0a 20 20 20 20 65 6e 64 0a 20 20 20 20 61 h). end. a
5110: 72 67 73 2e 63 6f 6e 63 61 74 28 25 77 28 2d 2d rgs.concat(%w(--
5120: 70 72 6f 63 20 2f 70 72 6f 63 20 2d 2d 64 65 76 proc /proc --dev
5130: 20 2f 64 65 76 20 2d 2d 74 6d 70 66 73 20 2f 74 /dev --tmpfs /t
5140: 6d 70 20 2d 2d 74 6d 70 66 73 20 2f 72 6f 6f 74 mp --tmpfs /root
5150: 29 29 0a 20 20 20 20 73 65 74 74 69 6e 67 73 2e )). settings.
5160: 68 6f 6d 65 73 2e 65 61 63 68 20 7b 20 7c 68 6f homes.each { |ho
5170: 73 74 2c 20 69 6e 73 69 64 65 7c 20 61 72 67 73 st, inside| args
5180: 2e 63 6f 6e 63 61 74 28 5b 22 2d 2d 62 69 6e 64 .concat(["--bind
5190: 22 2c 20 68 6f 73 74 2c 20 69 6e 73 69 64 65 5d ", host, inside]
51a0: 29 20 69 66 20 46 69 6c 65 2e 65 78 69 73 74 73 ) if File.exists
51b0: 3f 28 68 6f 73 74 29 20 7d 0a 20 20 20 20 73 65 ?(host) }. se
51c0: 74 74 69 6e 67 73 2e 74 6f 6f 6c 73 2e 65 61 63 ttings.tools.eac
51d0: 68 20 7b 20 7c 68 6f 73 74 2c 20 69 6e 73 69 64 h { |host, insid
51e0: 65 7c 20 61 72 67 73 2e 63 6f 6e 63 61 74 28 5b e| args.concat([
51f0: 22 2d 2d 72 6f 2d 62 69 6e 64 22 2c 20 68 6f 73 "--ro-bind", hos
5200: 74 2c 20 69 6e 73 69 64 65 5d 29 20 69 66 20 46 t, inside]) if F
5210: 69 6c 65 2e 65 78 69 73 74 73 3f 28 68 6f 73 74 ile.exists?(host
5220: 29 20 7d 0a 20 20 20 20 73 65 74 74 69 6e 67 73 ) }. settings
5230: 2e 72 65 61 64 5f 77 72 69 74 65 2e 65 61 63 68 .read_write.each
5240: 20 7b 20 7c 70 61 74 68 7c 20 61 72 67 73 2e 63 { |path| args.c
5250: 6f 6e 63 61 74 28 5b 22 2d 2d 62 69 6e 64 22 2c oncat(["--bind",
5260: 20 70 61 74 68 2c 20 70 61 74 68 5d 29 20 7d 0a path, path]) }.
5270: 20 20 20 20 61 72 67 73 2e 63 6f 6e 63 61 74 28 args.concat(
5280: 5b 22 2d 2d 62 69 6e 64 22 2c 20 72 6f 6f 74 2c ["--bind", root,
5290: 20 72 6f 6f 74 2c 20 46 69 6c 65 2e 6a 6f 69 6e root, File.join
52a0: 28 72 6f 6f 74 2c 20 22 63 75 72 72 65 6e 74 2f (root, "current/
52b0: 6f 63 78 32 22 29 2c 20 22 64 61 65 6d 6f 6e 22 ocx2"), "daemon"
52c0: 2c 20 46 69 6c 65 2e 6a 6f 69 6e 28 72 6f 6f 74 , File.join(root
52d0: 2c 20 22 6e 6f 64 65 2f 6e 6f 64 65 73 2e 6a 73 , "node/nodes.js
52e0: 6f 6e 22 29 5d 29 0a 20 20 20 20 23 20 52 65 66 on")]). # Ref
52f0: 75 73 65 20 61 6e 79 20 62 69 6e 64 20 74 68 61 use any bind tha
5300: 74 20 6f 76 65 72 6c 61 70 73 20 74 68 65 20 73 t overlaps the s
5310: 65 72 76 65 64 20 72 65 70 6f 73 69 74 6f 72 69 erved repositori
5320: 65 73 2c 20 66 6f 6c 6c 6f 77 69 6e 67 20 6c 69 es, following li
5330: 6e 6b 73 2e 0a 20 20 20 20 70 61 74 68 73 20 3d nks.. paths =
5340: 20 5b 73 65 74 74 69 6e 67 73 2e 72 65 70 6f 73 [settings.repos
5350: 69 74 6f 72 69 65 73 20 7c 7c 20 22 2f 6e 6f 6e itories || "/non
5360: 65 78 69 73 74 65 6e 74 2d 72 65 70 6f 73 69 74 existent-reposit
5370: 6f 72 69 65 73 22 5d 20 2b 20 61 72 67 73 2e 65 ories"] + args.e
5380: 61 63 68 5f 69 6e 64 65 78 2e 73 65 6c 65 63 74 ach_index.select
5390: 20 7b 20 7c 69 7c 20 7b 22 2d 2d 62 69 6e 64 22 { |i| {"--bind"
53a0: 2c 20 22 2d 2d 72 6f 2d 62 69 6e 64 22 7d 2e 69 , "--ro-bind"}.i
53b0: 6e 63 6c 75 64 65 73 3f 28 61 72 67 73 5b 69 5d ncludes?(args[i]
53c0: 29 20 7d 2e 6d 61 70 20 7b 20 7c 69 7c 20 61 72 ) }.map { |i| ar
53d0: 67 73 5b 69 20 2b 20 31 5d 20 7d 2e 74 6f 5f 61 gs[i + 1] }.to_a
53e0: 0a 20 20 20 20 70 61 74 68 73 2e 6d 61 70 21 20 . paths.map!
53f0: 64 6f 20 7c 70 61 74 68 7c 0a 20 20 20 20 20 20 do |path|.
5400: 6d 69 73 73 69 6e 67 20 3d 20 5b 5d 20 6f 66 20 missing = [] of
5410: 53 74 72 69 6e 67 0a 20 20 20 20 20 20 70 61 74 String. pat
5420: 68 20 3d 20 46 69 6c 65 2e 65 78 70 61 6e 64 5f h = File.expand_
5430: 70 61 74 68 28 70 61 74 68 29 0a 20 20 20 20 20 path(path).
5440: 20 75 6e 74 69 6c 20 46 69 6c 65 2e 65 78 69 73 until File.exis
5450: 74 73 3f 28 70 61 74 68 29 20 7c 7c 20 46 69 6c ts?(path) || Fil
5460: 65 2e 73 79 6d 6c 69 6e 6b 3f 28 70 61 74 68 29 e.symlink?(path)
5470: 0a 20 20 20 20 20 20 20 20 6d 69 73 73 69 6e 67 . missing
5480: 2e 75 6e 73 68 69 66 74 28 46 69 6c 65 2e 62 61 .unshift(File.ba
5490: 73 65 6e 61 6d 65 28 70 61 74 68 29 29 0a 20 20 sename(path)).
54a0: 20 20 20 20 20 20 70 61 74 68 20 3d 20 46 69 6c path = Fil
54b0: 65 2e 64 69 72 6e 61 6d 65 28 70 61 74 68 29 0a e.dirname(path).
54c0: 20 20 20 20 20 20 65 6e 64 0a 20 20 20 20 20 20 end.
54d0: 46 69 6c 65 2e 6a 6f 69 6e 28 5b 46 69 6c 65 2e File.join([File.
54e0: 72 65 61 6c 70 61 74 68 28 70 61 74 68 29 5d 20 realpath(path)]
54f0: 2b 20 6d 69 73 73 69 6e 67 29 2e 72 63 68 6f 70 + missing).rchop
5500: 28 27 2f 27 29 0a 20 20 20 20 65 6e 64 0a 20 20 ('/'). end.
5510: 20 20 72 65 70 6f 73 69 74 6f 72 79 20 3d 20 70 repository = p
5520: 61 74 68 73 2e 73 68 69 66 74 0a 20 20 20 20 70 aths.shift. p
5530: 61 74 68 73 2e 65 61 63 68 20 64 6f 20 7c 70 61 aths.each do |pa
5540: 74 68 7c 0a 20 20 20 20 20 20 61 62 6f 72 74 20 th|. abort
5550: 22 64 61 65 6d 6f 6e 20 62 6f 75 6e 64 20 70 61 "daemon bound pa
5560: 74 68 20 6f 76 65 72 6c 61 70 73 20 73 65 72 76 th overlaps serv
5570: 65 64 20 72 65 70 6f 73 69 74 6f 72 69 65 73 22 ed repositories"
5580: 2c 20 32 20 69 66 20 70 61 74 68 20 3d 3d 20 72 , 2 if path == r
5590: 65 70 6f 73 69 74 6f 72 79 20 7c 7c 20 70 61 74 epository || pat
55a0: 68 2e 73 74 61 72 74 73 5f 77 69 74 68 3f 28 72 h.starts_with?(r
55b0: 65 70 6f 73 69 74 6f 72 79 20 2b 20 22 2f 22 29 epository + "/")
55c0: 20 7c 7c 20 72 65 70 6f 73 69 74 6f 72 79 2e 73 || repository.s
55d0: 74 61 72 74 73 5f 77 69 74 68 3f 28 70 61 74 68 tarts_with?(path
55e0: 20 2b 20 22 2f 22 29 0a 20 20 20 20 65 6e 64 0a + "/"). end.
55f0: 20 20 65 6c 73 65 0a 20 20 20 20 61 62 6f 72 74 else. abort
5600: 20 22 75 6e 72 65 63 6f 67 6e 69 73 65 64 20 6d "unrecognised m
5610: 6f 64 65 22 2c 20 32 0a 20 20 65 6e 64 0a 20 20 ode", 2. end.
5620: 23 20 45 78 65 63 20 64 69 72 65 63 74 6c 79 3a # Exec directly:
5630: 20 74 68 65 20 72 65 63 65 69 70 74 20 43 47 49 the receipt CGI
5640: 20 68 61 73 20 63 6c 6f 73 65 64 20 74 68 65 20 has closed the
5650: 72 75 6e 74 69 6d 65 27 73 20 64 65 73 63 72 69 runtime's descri
5660: 70 74 6f 72 73 2e 0a 20 20 61 72 67 76 20 3d 20 ptors.. argv =
5670: 28 5b 22 2f 75 73 72 2f 62 69 6e 2f 62 77 72 61 (["/usr/bin/bwra
5680: 70 22 5d 20 2b 20 61 72 67 73 29 2e 6d 61 70 28 p"] + args).map(
5690: 26 2e 74 6f 5f 75 6e 73 61 66 65 29 20 2b 20 5b &.to_unsafe) + [
56a0: 50 6f 69 6e 74 65 72 28 55 49 6e 74 38 29 2e 6e Pointer(UInt8).n
56b0: 75 6c 6c 5d 0a 20 20 4c 69 62 43 2e 65 78 65 63 ull]. LibC.exec
56c0: 76 28 22 2f 75 73 72 2f 62 69 6e 2f 62 77 72 61 v("/usr/bin/bwra
56d0: 70 22 2c 20 61 72 67 76 2e 74 6f 5f 75 6e 73 61 p", argv.to_unsa
56e0: 66 65 29 0a 20 20 72 61 69 73 65 20 49 4f 3a 3a fe). raise IO::
56f0: 45 72 72 6f 72 2e 66 72 6f 6d 5f 65 72 72 6e 6f Error.from_errno
5700: 28 22 65 78 65 63 76 22 29 0a 72 65 73 63 75 65 ("execv").rescue
5710: 20 65 78 20 3a 20 41 72 67 75 6d 65 6e 74 45 72 ex : ArgumentEr
5720: 72 6f 72 20 7c 20 49 4f 3a 3a 45 72 72 6f 72 0a ror | IO::Error.
5730: 20 20 53 54 44 45 52 52 2e 70 75 74 73 20 65 78 STDERR.puts ex
5740: 2e 6d 65 73 73 61 67 65 0a 20 20 65 78 69 74 20 .message. exit
5750: 32 0a 65 6e 64 0a 00 00 00 00 00 00 00 00 00 00 2.end...........
5760: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5770: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
57a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
57b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
57c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
57d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
57e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
57f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5800: 73 63 72 69 70 74 73 2d 66 6f 72 2d 72 65 76 69 scripts-for-revi
5810: 65 77 2d 33 2f 73 79 6e 63 2d 66 6f 73 73 69 6c ew-3/sync-fossil
5820: 2e 63 72 00 00 00 00 00 00 00 00 00 00 00 00 00 .cr.............
5830: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5840: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5850: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5860: 00 00 00 00 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000
5870: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
5880: 30 30 30 34 34 34 35 00 31 35 32 37 30 36 36 34 0004445.15270664
5890: 36 31 33 00 30 31 36 33 30 36 00 20 30 00 00 00 613.016306. 0...
58a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
58b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
58c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
58d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
58e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
58f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5900: 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
5910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5920: 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
5930: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5940: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5950: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5960: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5970: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5990: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
59a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
59b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
59c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
59d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
59e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
59f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
5a00: 23 20 41 67 65 6e 74 73 3a 20 64 6f 20 6e 6f 74 # Agents: do not
5a10: 20 63 68 61 6e 67 65 20 74 68 69 73 20 66 69 6c change this fil
5a20: 65 20 6f 6e 20 61 6e 79 20 62 72 61 6e 63 68 20 e on any branch
5a30: 77 69 74 68 6f 75 74 20 74 68 65 20 6d 61 69 6e without the main
5a40: 74 61 69 6e 65 72 27 73 20 65 78 70 6c 69 63 69 tainer's explici
5a50: 74 20 61 70 70 72 6f 76 61 6c 20 6f 6e 20 74 68 t approval on th
5a60: 65 20 72 65 63 6f 72 64 2e 0a 23 20 53 79 6e 63 e record..# Sync
5a70: 20 6f 72 20 63 6c 6f 6e 65 20 72 65 70 6f 73 69 or clone reposi
5a80: 74 6f 72 69 65 73 3b 20 73 65 74 74 69 6e 67 73 tories; settings
5a90: 20 61 72 65 20 69 6e 20 74 68 65 20 73 65 72 76 are in the serv
5aa0: 65 72 73 2e 6a 73 6f 6e 20 62 65 73 69 64 65 20 ers.json beside
5ab0: 74 68 69 73 20 70 72 6f 67 72 61 6d 2e 0a 23 20 this program..#
5ac0: 54 68 65 20 6d 61 69 6e 74 61 69 6e 65 72 20 72 The maintainer r
5ad0: 75 6e 73 20 62 69 6e 2f 73 79 6e 63 2d 66 6f 73 uns bin/sync-fos
5ae0: 73 69 6c 20 61 66 74 65 72 20 73 68 61 72 64 73 sil after shards
5af0: 20 62 75 69 6c 64 20 73 79 6e 63 2d 66 6f 73 73 build sync-foss
5b00: 69 6c 2e 0a 72 65 71 75 69 72 65 20 22 6a 73 6f il..require "jso
5b10: 6e 22 0a 53 45 52 56 45 52 20 3d 20 22 68 74 74 n".SERVER = "htt
5b20: 70 73 3a 2f 2f 6f 6c 6c 61 6d 61 2e 6f 70 65 6e ps://ollama.open
5b30: 62 65 61 67 6c 65 2e 6f 72 67 22 20 23 20 77 68 beagle.org" # wh
5b40: 65 72 65 20 63 6c 6f 6e 65 73 20 63 6f 6d 65 20 ere clones come
5b50: 66 72 6f 6d 0a 0a 73 74 72 75 63 74 20 53 65 72 from..struct Ser
5b60: 76 65 72 0a 20 20 69 6e 63 6c 75 64 65 20 4a 53 ver. include JS
5b70: 4f 4e 3a 3a 53 65 72 69 61 6c 69 7a 61 62 6c 65 ON::Serializable
5b80: 0a 20 20 67 65 74 74 65 72 20 73 79 6e 63 20 3a . getter sync :
5b90: 20 41 72 72 61 79 28 53 74 72 69 6e 67 29 3f 0a Array(String)?.
5ba0: 65 6e 64 0a 0a 66 69 6c 65 20 3d 20 46 69 6c 65 end..file = File
5bb0: 2e 6a 6f 69 6e 28 46 69 6c 65 2e 64 69 72 6e 61 .join(File.dirna
5bc0: 6d 65 28 50 72 6f 63 65 73 73 2e 65 78 65 63 75 me(Process.execu
5bd0: 74 61 62 6c 65 5f 70 61 74 68 2e 6e 6f 74 5f 6e table_path.not_n
5be0: 69 6c 21 29 2c 20 22 73 65 72 76 65 72 73 2e 6a il!), "servers.j
5bf0: 73 6f 6e 22 29 0a 62 65 67 69 6e 0a 20 20 73 65 son").begin. se
5c00: 72 76 65 72 73 20 3d 20 48 61 73 68 28 53 74 72 rvers = Hash(Str
5c10: 69 6e 67 2c 20 4a 53 4f 4e 3a 3a 41 6e 79 29 2e ing, JSON::Any).
5c20: 66 72 6f 6d 5f 6a 73 6f 6e 28 46 69 6c 65 2e 72 from_json(File.r
5c30: 65 61 64 28 66 69 6c 65 29 29 0a 20 20 6c 6f 63 ead(file)). loc
5c40: 61 6c 20 3d 20 73 65 72 76 65 72 73 5b 53 79 73 al = servers[Sys
5c50: 74 65 6d 2e 68 6f 73 74 6e 61 6d 65 5d 3f 2e 74 tem.hostname]?.t
5c60: 72 79 20 7b 20 7c 65 6e 74 72 79 7c 20 53 65 72 ry { |entry| Ser
5c70: 76 65 72 2e 66 72 6f 6d 5f 6a 73 6f 6e 28 65 6e ver.from_json(en
5c80: 74 72 79 2e 74 6f 5f 6a 73 6f 6e 29 20 7d 0a 20 try.to_json) }.
5c90: 20 64 65 66 61 75 6c 74 20 3d 20 73 65 72 76 65 default = serve
5ca0: 72 73 5b 22 2a 22 5d 3f 2e 74 72 79 20 7b 20 7c rs["*"]?.try { |
5cb0: 65 6e 74 72 79 7c 20 53 65 72 76 65 72 2e 66 72 entry| Server.fr
5cc0: 6f 6d 5f 6a 73 6f 6e 28 65 6e 74 72 79 2e 74 6f om_json(entry.to
5cd0: 5f 6a 73 6f 6e 29 20 7d 0a 20 20 72 65 70 6f 73 _json) }. repos
5ce0: 69 74 6f 72 69 65 73 20 3d 20 6c 6f 63 61 6c 2e itories = local.
5cf0: 74 72 79 28 26 2e 73 79 6e 63 29 20 7c 7c 20 64 try(&.sync) || d
5d00: 65 66 61 75 6c 74 2e 74 72 79 28 26 2e 73 79 6e efault.try(&.syn
5d10: 63 29 20 7c 7c 20 61 62 6f 72 74 20 22 23 7b 66 c) || abort "#{f
5d20: 69 6c 65 7d 3a 20 6d 69 73 73 69 6e 67 20 73 79 ile}: missing sy
5d30: 6e 63 22 2c 20 32 0a 72 65 73 63 75 65 20 65 78 nc", 2.rescue ex
5d40: 20 3a 20 49 4f 3a 3a 45 72 72 6f 72 20 7c 20 4a : IO::Error | J
5d50: 53 4f 4e 3a 3a 50 61 72 73 65 45 78 63 65 70 74 SON::ParseExcept
5d60: 69 6f 6e 0a 20 20 61 62 6f 72 74 20 22 23 7b 66 ion. abort "#{f
5d70: 69 6c 65 7d 3a 20 63 61 6e 6e 6f 74 20 72 65 61 ile}: cannot rea
5d80: 64 20 73 79 6e 63 3a 20 23 7b 65 78 2e 6d 65 73 d sync: #{ex.mes
5d90: 73 61 67 65 2e 74 6f 5f 73 2e 6c 69 6e 65 73 2e sage.to_s.lines.
5da0: 66 69 72 73 74 7d 22 2c 20 32 0a 65 6e 64 0a 0a first}", 2.end..
5db0: 23 20 46 69 6e 64 20 74 68 65 20 64 69 72 65 63 # Find the direc
5dc0: 74 6f 72 79 20 61 62 6f 76 65 20 74 68 69 73 20 tory above this
5dd0: 63 68 65 63 6b 6f 75 74 2e 0a 68 6f 73 74 20 3d checkout..host =
5de0: 20 53 79 73 74 65 6d 2e 68 6f 73 74 6e 61 6d 65 System.hostname
5df0: 0a 6d 65 20 3d 20 50 72 6f 63 65 73 73 2e 65 78 .me = Process.ex
5e00: 65 63 75 74 61 62 6c 65 5f 70 61 74 68 20 7c 7c ecutable_path ||
5e10: 20 61 62 6f 72 74 20 22 63 61 6e 6e 6f 74 20 74 abort "cannot t
5e20: 65 6c 6c 20 77 68 65 72 65 20 74 68 69 73 20 70 ell where this p
5e30: 72 6f 67 72 61 6d 20 69 73 22 0a 62 61 73 65 64 rogram is".based
5e40: 69 72 20 3d 20 46 69 6c 65 2e 72 65 61 6c 70 61 ir = File.realpa
5e50: 74 68 28 46 69 6c 65 2e 6a 6f 69 6e 28 46 69 6c th(File.join(Fil
5e60: 65 2e 64 69 72 6e 61 6d 65 28 6d 65 29 2c 20 22 e.dirname(me), "
5e70: 2e 2e 22 2c 20 22 2e 2e 22 29 29 0a 70 75 74 73 ..", "..")).puts
5e80: 20 22 52 75 6e 6e 69 6e 67 20 6f 6e 20 23 7b 68 "Running on #{h
5e90: 6f 73 74 7d 22 0a 70 75 74 73 20 22 52 75 6e 6e ost}".puts "Runn
5ea0: 69 6e 67 20 66 72 6f 6d 20 23 7b 62 61 73 65 64 ing from #{based
5eb0: 69 72 7d 22 0a 0a 23 20 52 65 61 64 20 46 6f 73 ir}"..# Read Fos
5ec0: 73 69 6c 27 73 20 73 74 61 74 75 73 20 61 6e 64 sil's status and
5ed0: 20 77 6f 72 64 73 20 74 6f 20 64 65 63 69 64 65 words to decide
5ee0: 20 77 68 65 74 68 65 72 20 69 74 20 66 61 69 6c whether it fail
5ef0: 65 64 2e 0a 64 65 66 20 66 61 69 6c 75 72 65 28 ed..def failure(
5f00: 73 74 61 74 75 73 20 3a 20 50 72 6f 63 65 73 73 status : Process
5f10: 3a 3a 53 74 61 74 75 73 2c 20 6f 75 74 70 75 74 ::Status, output
5f20: 20 3a 20 53 74 72 69 6e 67 29 20 3a 20 53 74 72 : String) : Str
5f30: 69 6e 67 3f 0a 20 20 72 65 74 75 72 6e 20 22 66 ing?. return "f
5f40: 6f 73 73 69 6c 20 65 6e 64 65 64 20 61 62 6e 6f ossil ended abno
5f50: 72 6d 61 6c 6c 79 20 28 23 7b 73 74 61 74 75 73 rmally (#{status
5f60: 2e 65 78 69 74 5f 72 65 61 73 6f 6e 7d 29 22 20 .exit_reason})"
5f70: 75 6e 6c 65 73 73 20 73 74 61 74 75 73 2e 6e 6f unless status.no
5f80: 72 6d 61 6c 5f 65 78 69 74 3f 0a 20 20 72 65 74 rmal_exit?. ret
5f90: 75 72 6e 20 22 66 6f 73 73 69 6c 20 65 78 69 74 urn "fossil exit
5fa0: 65 64 20 23 7b 73 74 61 74 75 73 2e 65 78 69 74 ed #{status.exit
5fb0: 5f 63 6f 64 65 7d 22 20 75 6e 6c 65 73 73 20 73 _code}" unless s
5fc0: 74 61 74 75 73 2e 73 75 63 63 65 73 73 3f 0a 20 tatus.success?.
5fd0: 20 69 66 20 6c 69 6e 65 20 3d 20 6f 75 74 70 75 if line = outpu
5fe0: 74 2e 65 61 63 68 5f 6c 69 6e 65 2e 6d 61 70 28 t.each_line.map(
5ff0: 26 2e 73 70 6c 69 74 28 27 5c 72 27 29 2e 6c 61 &.split('\r').la
6000: 73 74 2e 73 74 72 69 70 29 2e 66 69 6e 64 28 26 st.strip).find(&
6010: 2e 73 74 61 72 74 73 5f 77 69 74 68 3f 28 22 45 .starts_with?("E
6020: 72 72 6f 72 3a 22 29 29 0a 20 20 20 20 72 65 74 rror:")). ret
6030: 75 72 6e 20 6c 69 6e 65 0a 20 20 65 6e 64 0a 20 urn line. end.
6040: 20 22 69 74 20 6e 65 76 65 72 20 72 65 61 63 68 "it never reach
6050: 65 64 20 74 68 65 20 73 65 72 76 65 72 20 28 52 ed the server (R
6060: 6f 75 6e 64 2d 74 72 69 70 73 3a 20 30 29 22 20 ound-trips: 0)"
6070: 69 66 20 6f 75 74 70 75 74 2e 69 6e 63 6c 75 64 if output.includ
6080: 65 73 3f 28 22 52 6f 75 6e 64 2d 74 72 69 70 73 es?("Round-trips
6090: 3a 20 30 20 22 29 0a 65 6e 64 0a 0a 23 20 53 79 : 0 ").end..# Sy
60a0: 6e 63 20 6f 72 20 63 6c 6f 6e 65 20 65 61 63 68 nc or clone each
60b0: 20 72 65 70 6f 73 69 74 6f 72 79 3b 20 73 74 6f repository; sto
60c0: 70 20 61 74 20 74 68 65 20 66 69 72 73 74 20 66 p at the first f
60d0: 61 69 6c 75 72 65 2e 0a 72 65 70 6f 73 69 74 6f ailure..reposito
60e0: 72 69 65 73 2e 65 61 63 68 20 64 6f 20 7c 64 7c ries.each do |d|
60f0: 0a 20 20 70 75 74 73 20 22 5c 6e 5c 6e 5c 74 2a . puts "\n\n\t*
6100: 2a 2a 2a 5b 20 23 7b 62 61 73 65 64 69 72 7d 2f ***[ #{basedir}/
6110: 23 7b 64 7d 20 5d 2a 2a 2a 2a 5c 6e 5c 6e 22 0a #{d} ]****\n\n".
6120: 20 20 64 69 72 20 3d 20 46 69 6c 65 2e 6a 6f 69 dir = File.joi
6130: 6e 28 62 61 73 65 64 69 72 2c 20 64 29 0a 20 20 n(basedir, d).
6140: 23 20 53 68 6f 77 20 61 6e 64 20 6b 65 65 70 20 # Show and keep
6150: 46 6f 73 73 69 6c 27 73 20 6f 75 74 70 75 74 2e Fossil's output.
6160: 0a 20 20 73 61 69 64 20 3d 20 49 4f 3a 3a 4d 65 . said = IO::Me
6170: 6d 6f 72 79 2e 6e 65 77 0a 20 20 73 68 6f 77 6e mory.new. shown
6180: 20 3d 20 49 4f 3a 3a 4d 75 6c 74 69 57 72 69 74 = IO::MultiWrit
6190: 65 72 2e 6e 65 77 28 53 54 44 4f 55 54 2c 20 73 er.new(STDOUT, s
61a0: 61 69 64 29 0a 20 20 73 74 61 74 75 73 20 3d 20 aid). status =
61b0: 69 66 20 44 69 72 2e 65 78 69 73 74 73 3f 28 64 if Dir.exists?(d
61c0: 69 72 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 ir).
61d0: 20 50 72 6f 63 65 73 73 2e 72 75 6e 28 22 66 6f Process.run("fo
61e0: 73 73 69 6c 22 2c 20 5b 22 73 79 6e 63 22 2c 20 ssil", ["sync",
61f0: 22 2d 2d 61 6c 6c 22 5d 2c 20 63 68 64 69 72 3a "--all"], chdir:
6200: 20 64 69 72 2c 20 6f 75 74 70 75 74 3a 20 73 68 dir, output: sh
6210: 6f 77 6e 2c 20 65 72 72 6f 72 3a 20 73 68 6f 77 own, error: show
6220: 6e 29 0a 20 20 20 20 20 20 20 20 20 20 20 65 6c n). el
6230: 73 65 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 se.
6240: 50 72 6f 63 65 73 73 2e 72 75 6e 28 22 66 6f 73 Process.run("fos
6250: 73 69 6c 22 2c 20 5b 22 63 6c 6f 6e 65 22 2c 20 sil", ["clone",
6260: 22 23 7b 53 45 52 56 45 52 7d 2f 23 7b 64 7d 22 "#{SERVER}/#{d}"
6270: 5d 2c 20 63 68 64 69 72 3a 20 62 61 73 65 64 69 ], chdir: basedi
6280: 72 2c 20 6f 75 74 70 75 74 3a 20 73 68 6f 77 6e r, output: shown
6290: 2c 20 65 72 72 6f 72 3a 20 73 68 6f 77 6e 29 0a , error: shown).
62a0: 20 20 20 20 20 20 20 20 20 20 20 65 6e 64 0a 20 end.
62b0: 20 69 66 20 72 65 61 73 6f 6e 20 3d 20 66 61 69 if reason = fai
62c0: 6c 75 72 65 28 73 74 61 74 75 73 2c 20 73 61 69 lure(status, sai
62d0: 64 2e 74 6f 5f 73 29 0a 20 20 20 20 53 54 44 45 d.to_s). STDE
62e0: 52 52 2e 70 75 74 73 20 22 5c 6e 73 79 6e 63 2d RR.puts "\nsync-
62f0: 66 6f 73 73 69 6c 3a 20 23 7b 64 7d 20 66 61 69 fossil: #{d} fai
6300: 6c 65 64 3a 20 23 7b 72 65 61 73 6f 6e 7d 22 0a led: #{reason}".
6310: 20 20 20 20 65 78 69 74 20 31 0a 20 20 65 6e 64 exit 1. end
6320: 0a 65 6e 64 0a 00 00 00 00 00 00 00 00 00 00 00 .end............
6330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
63a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
63b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
63c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
63d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
63e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
63f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6400: 73 63 72 69 70 74 73 2d 66 6f 72 2d 72 65 76 69 scripts-for-revi
6410: 65 77 2d 33 2f 73 65 72 76 65 72 73 2e 6a 73 6f ew-3/servers.jso
6420: 6e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 n...............
6430: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6440: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6450: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6460: 00 00 00 00 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000
6470: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
6480: 30 30 30 36 32 36 36 00 31 35 32 37 30 36 36 34 0006266.15270664
6490: 36 31 33 00 30 31 36 30 37 36 00 20 30 00 00 00 613.016076. 0...
64a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
64b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
64c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
64d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
64e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
64f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6500: 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
6510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6520: 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
6530: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6590: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
65a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
65b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
65c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
65d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
65e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
65f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
6600: 7b 0a 20 20 22 5f 61 62 6f 75 74 22 3a 20 22 48 {. "_about": "H
6610: 6f 73 74 20 64 65 70 6c 6f 79 6d 65 6e 74 20 73 ost deployment s
6620: 65 74 74 69 6e 67 73 3b 20 63 6f 70 79 20 73 65 ettings; copy se
6630: 72 76 65 72 73 2e 6a 73 6f 6e 20 62 65 73 69 64 rvers.json besid
6640: 65 20 65 61 63 68 20 64 65 70 6c 6f 79 65 64 20 e each deployed
6650: 70 72 6f 67 72 61 6d 2e 22 2c 0a 20 20 22 69 70 program.",. "ip
6660: 2d 31 37 32 2d 33 31 2d 31 37 2d 31 37 37 2e 75 -172-31-17-177.u
6670: 73 2d 77 65 73 74 2d 32 2e 63 6f 6d 70 75 74 65 s-west-2.compute
6680: 2e 69 6e 74 65 72 6e 61 6c 22 3a 20 7b 0a 20 20 .internal": {.
6690: 20 20 22 66 6f 73 73 69 6c 5f 73 65 72 76 65 72 "fossil_server
66a0: 22 3a 20 7b 0a 20 20 20 20 20 20 22 66 6f 73 73 ": {. "foss
66b0: 69 6c 22 3a 20 22 2f 75 73 72 2f 62 69 6e 2f 66 il": "/usr/bin/f
66c0: 6f 73 73 69 6c 22 2c 0a 20 20 20 20 20 20 22 61 ossil",. "a
66d0: 72 67 73 22 3a 20 5b 0a 20 20 20 20 20 20 20 20 rgs": [.
66e0: 22 73 65 72 76 65 72 22 2c 0a 20 20 20 20 20 20 "server",.
66f0: 20 20 22 2d 2d 62 61 73 65 75 72 6c 22 2c 20 22 "--baseurl", "
6700: 68 74 74 70 73 3a 2f 2f 6f 6c 6c 61 6d 61 2e 6f https://ollama.o
6710: 70 65 6e 62 65 61 67 6c 65 2e 6f 72 67 22 2c 0a penbeagle.org",.
6720: 20 20 20 20 20 20 20 20 22 2d 2d 70 6f 72 74 22 "--port"
6730: 2c 20 22 34 34 33 22 2c 0a 20 20 20 20 20 20 20 , "443",.
6740: 20 22 2d 2d 6a 73 6d 6f 64 65 22 2c 20 22 62 75 "--jsmode", "bu
6750: 6e 64 6c 65 64 22 2c 0a 20 20 20 20 20 20 20 20 ndled",.
6760: 22 2d 2d 63 65 72 74 22 2c 20 22 2f 65 74 63 2f "--cert", "/etc/
6770: 6c 65 74 73 65 6e 63 72 79 70 74 2f 6c 69 76 65 letsencrypt/live
6780: 2f 6f 6c 6c 61 6d 61 2e 6f 70 65 6e 62 65 61 67 /ollama.openbeag
6790: 6c 65 2e 6f 72 67 2f 66 75 6c 6c 63 68 61 69 6e le.org/fullchain
67a0: 2e 70 65 6d 22 2c 0a 20 20 20 20 20 20 20 20 22 .pem",. "
67b0: 2d 2d 70 6b 65 79 22 2c 20 22 2f 65 74 63 2f 6c --pkey", "/etc/l
67c0: 65 74 73 65 6e 63 72 79 70 74 2f 6c 69 76 65 2f etsencrypt/live/
67d0: 6f 6c 6c 61 6d 61 2e 6f 70 65 6e 62 65 61 67 6c ollama.openbeagl
67e0: 65 2e 6f 72 67 2f 70 72 69 76 6b 65 79 2e 70 65 e.org/privkey.pe
67f0: 6d 22 2c 0a 20 20 20 20 20 20 20 20 22 2d 2d 61 m",. "--a
6800: 63 6d 65 22 2c 0a 20 20 20 20 20 20 20 20 22 2d cme",. "-
6810: 2d 6e 6f 6a 61 69 6c 22 2c 0a 20 20 20 20 20 20 -nojail",.
6820: 20 20 22 2d 2d 72 65 70 6f 6c 69 73 74 22 2c 20 "--repolist",
6830: 22 2f 76 61 72 2f 6c 69 62 2f 66 6f 73 73 69 6c "/var/lib/fossil
6840: 22 2c 0a 20 20 20 20 20 20 20 20 22 2d 2d 65 78 ",. "--ex
6850: 74 72 6f 6f 74 22 2c 20 22 2f 76 61 72 2f 77 77 troot", "/var/ww
6860: 77 2f 63 67 69 2d 62 69 6e 22 2c 0a 20 20 20 20 w/cgi-bin",.
6870: 20 20 20 20 22 2d 2d 6e 6f 74 66 6f 75 6e 64 22 "--notfound"
6880: 2c 20 22 68 74 74 70 73 3a 2f 2f 6f 6c 6c 61 6d , "https://ollam
6890: 61 2e 6f 70 65 6e 62 65 61 67 6c 65 2e 6f 72 67 a.openbeagle.org
68a0: 2f 69 6e 64 65 78 2e 68 74 6d 6c 22 2c 0a 20 20 /index.html",.
68b0: 20 20 20 20 20 20 22 2d 2d 66 69 6c 65 73 22 2c "--files",
68c0: 20 22 2a 2e 69 63 6f 2c 2a 2e 68 74 6d 6c 22 2c "*.ico,*.html",
68d0: 0a 20 20 20 20 20 20 20 20 22 2d 2d 65 72 72 6f . "--erro
68e0: 72 6c 6f 67 22 2c 20 22 2f 76 61 72 2f 6c 6f 67 rlog", "/var/log
68f0: 2f 66 6f 73 73 69 6c 2e 65 72 72 2e 6c 6f 67 22 /fossil.err.log"
6900: 0a 20 20 20 20 20 20 5d 0a 20 20 20 20 7d 2c 0a . ]. },.
6910: 20 20 20 20 22 6f 63 78 22 3a 20 7b 0a 20 20 20 "ocx": {.
6920: 20 20 20 22 72 65 70 6f 73 69 74 6f 72 69 65 73 "repositories
6930: 22 3a 20 22 2f 76 61 72 2f 6c 69 62 2f 66 6f 73 ": "/var/lib/fos
6940: 73 69 6c 22 2c 0a 20 20 20 20 20 20 22 73 6f 63 sil",. "soc
6950: 6b 65 74 5f 64 69 72 22 3a 20 22 2f 72 75 6e 2f ket_dir": "/run/
6960: 6f 63 78 22 2c 0a 20 20 20 20 20 20 22 72 65 6c ocx",. "rel
6970: 65 61 73 65 73 22 3a 20 22 2f 76 61 72 2f 6c 69 eases": "/var/li
6980: 62 2f 6f 63 78 2f 72 65 6c 65 61 73 65 32 22 2c b/ocx/release2",
6990: 0a 20 20 20 20 20 20 22 64 61 65 6d 6f 6e 5f 72 . "daemon_r
69a0: 6f 6f 74 22 3a 20 22 2f 76 61 72 2f 6c 69 62 2f oot": "/var/lib/
69b0: 6f 63 78 2f 61 67 65 6e 74 73 2d 64 61 65 6d 6f ocx/agents-daemo
69c0: 6e 22 2c 0a 20 20 20 20 20 20 22 68 6f 6d 65 73 n",. "homes
69d0: 22 3a 20 7b 0a 20 20 20 20 20 20 20 20 22 2f 68 ": {. "/h
69e0: 6f 6d 65 2f 6f 63 78 2f 2e 63 6f 64 65 78 22 3a ome/ocx/.codex":
69f0: 20 22 2f 72 6f 6f 74 2f 2e 63 6f 64 65 78 22 2c "/root/.codex",
6a00: 0a 20 20 20 20 20 20 20 20 22 2f 68 6f 6d 65 2f . "/home/
6a10: 6f 63 78 2f 2e 63 6c 61 75 64 65 22 3a 20 22 2f ocx/.claude": "/
6a20: 72 6f 6f 74 2f 2e 63 6c 61 75 64 65 22 2c 0a 20 root/.claude",.
6a30: 20 20 20 20 20 20 20 22 2f 68 6f 6d 65 2f 6f 63 "/home/oc
6a40: 78 2f 2e 63 6c 61 75 64 65 2e 6a 73 6f 6e 22 3a x/.claude.json":
6a50: 20 22 2f 72 6f 6f 74 2f 2e 63 6c 61 75 64 65 2e "/root/.claude.
6a60: 6a 73 6f 6e 22 0a 20 20 20 20 20 20 7d 2c 0a 20 json". },.
6a70: 20 20 20 20 20 22 74 6f 6f 6c 73 22 3a 20 7b 0a "tools": {.
6a80: 20 20 20 20 20 20 20 20 22 2f 68 6f 6d 65 2f 6f "/home/o
6a90: 63 78 2f 2e 6c 6f 63 61 6c 22 3a 20 22 2f 72 6f cx/.local": "/ro
6aa0: 6f 74 2f 2e 6c 6f 63 61 6c 22 0a 20 20 20 20 20 ot/.local".
6ab0: 20 7d 2c 0a 20 20 20 20 20 20 22 6c 61 75 6e 63 },. "launc
6ac0: 68 65 72 22 3a 20 22 2f 75 73 72 2f 6c 6f 63 61 her": "/usr/loca
6ad0: 6c 2f 6c 69 62 65 78 65 63 2f 6f 63 78 2f 73 74 l/libexec/ocx/st
6ae0: 61 72 74 2d 6f 63 78 22 0a 20 20 20 20 7d 0a 20 art-ocx". }.
6af0: 20 7d 2c 0a 20 20 22 62 65 61 67 6c 65 79 2d 73 },. "beagley-s
6b00: 73 64 22 3a 20 7b 0a 20 20 20 20 22 66 6f 73 73 sd": {. "foss
6b10: 69 6c 5f 73 65 72 76 65 72 22 3a 20 7b 0a 20 20 il_server": {.
6b20: 20 20 20 20 22 61 72 67 73 22 3a 20 5b 0a 20 20 "args": [.
6b30: 20 20 20 20 20 20 22 73 65 72 76 65 72 22 2c 0a "server",.
6b40: 20 20 20 20 20 20 20 20 22 2d 2d 70 6f 72 74 22 "--port"
6b50: 2c 20 22 34 34 33 22 2c 0a 20 20 20 20 20 20 20 , "443",.
6b60: 20 22 2d 2d 63 65 72 74 22 2c 20 22 24 48 4f 4d "--cert", "$HOM
6b70: 45 2f 2e 63 6f 6e 66 69 67 2f 66 6f 73 73 69 6c E/.config/fossil
6b80: 2f 74 6c 73 2f 63 65 72 74 69 66 69 63 61 74 65 /tls/certificate
6b90: 2e 70 65 6d 22 2c 0a 20 20 20 20 20 20 20 20 22 .pem",. "
6ba0: 2d 2d 70 6b 65 79 22 2c 20 22 24 48 4f 4d 45 2f --pkey", "$HOME/
6bb0: 2e 63 6f 6e 66 69 67 2f 66 6f 73 73 69 6c 2f 74 .config/fossil/t
6bc0: 6c 73 2f 70 72 69 76 61 74 65 2d 6b 65 79 2e 70 ls/private-key.p
6bd0: 65 6d 22 2c 0a 20 20 20 20 20 20 20 20 22 2d 2d em",. "--
6be0: 6a 73 6d 6f 64 65 22 2c 20 22 62 75 6e 64 6c 65 jsmode", "bundle
6bf0: 64 22 2c 0a 20 20 20 20 20 20 20 20 22 2d 2d 72 d",. "--r
6c00: 65 70 6f 6c 69 73 74 22 2c 20 22 24 42 41 53 45 epolist", "$BASE
6c10: 44 49 52 22 2c 0a 20 20 20 20 20 20 20 20 22 2d DIR",. "-
6c20: 2d 65 78 74 72 6f 6f 74 22 2c 20 22 24 48 4f 4d -extroot", "$HOM
6c30: 45 2f 2e 6c 6f 63 61 6c 2f 63 67 69 2d 62 69 6e E/.local/cgi-bin
6c40: 22 2c 0a 20 20 20 20 20 20 20 20 22 2d 2d 6e 6f ",. "--no
6c50: 6a 61 69 6c 22 2c 0a 20 20 20 20 20 20 20 20 22 jail",. "
6c60: 2d 2d 73 6b 69 6e 22 2c 20 22 64 61 72 6b 6d 6f --skin", "darkmo
6c70: 64 65 22 2c 0a 20 20 20 20 20 20 20 20 22 2d 2d de",. "--
6c80: 65 72 72 6f 72 6c 6f 67 22 2c 20 22 24 42 41 53 errorlog", "$BAS
6c90: 45 44 49 52 2f 66 6f 73 73 69 6c 2e 65 72 72 2e EDIR/fossil.err.
6ca0: 6c 6f 67 22 0a 20 20 20 20 20 20 5d 2c 0a 20 20 log". ],.
6cb0: 20 20 20 20 22 73 68 6f 77 5f 63 61 70 61 62 69 "show_capabi
6cc0: 6c 69 74 69 65 73 22 3a 20 74 72 75 65 0a 20 20 lities": true.
6cd0: 20 20 7d 0a 20 20 7d 2c 0a 20 20 22 62 65 61 67 }. },. "beag
6ce0: 6c 65 62 61 64 67 65 22 3a 20 7b 0a 20 20 20 20 lebadge": {.
6cf0: 22 66 6f 73 73 69 6c 5f 73 65 72 76 65 72 22 3a "fossil_server":
6d00: 20 7b 0a 20 20 20 20 20 20 22 61 72 67 73 22 3a {. "args":
6d10: 20 5b 0a 20 20 20 20 20 20 20 20 22 73 65 72 76 [. "serv
6d20: 65 72 22 2c 0a 20 20 20 20 20 20 20 20 22 2d 2d er",. "--
6d30: 70 6f 72 74 22 2c 20 22 38 30 22 2c 0a 20 20 20 port", "80",.
6d40: 20 20 20 20 20 22 2d 2d 6a 73 6d 6f 64 65 22 2c "--jsmode",
6d50: 20 22 62 75 6e 64 6c 65 64 22 2c 0a 20 20 20 20 "bundled",.
6d60: 20 20 20 20 22 2d 2d 72 65 70 6f 6c 69 73 74 22 "--repolist"
6d70: 2c 20 22 24 42 41 53 45 44 49 52 22 2c 0a 20 20 , "$BASEDIR",.
6d80: 20 20 20 20 20 20 22 2d 2d 6e 6f 6a 61 69 6c 22 "--nojail"
6d90: 2c 0a 20 20 20 20 20 20 20 20 22 2d 2d 65 72 72 ,. "--err
6da0: 6f 72 6c 6f 67 22 2c 20 22 24 42 41 53 45 44 49 orlog", "$BASEDI
6db0: 52 2f 66 6f 73 73 69 6c 2e 65 72 72 2e 6c 6f 67 R/fossil.err.log
6dc0: 22 0a 20 20 20 20 20 20 5d 0a 20 20 20 20 7d 0a ". ]. }.
6dd0: 20 20 7d 2c 0a 20 20 22 73 6c 6f 74 63 61 72 22 },. "slotcar"
6de0: 3a 20 7b 0a 20 20 20 20 22 66 6f 73 73 69 6c 5f : {. "fossil_
6df0: 73 65 72 76 65 72 22 3a 20 7b 0a 20 20 20 20 20 server": {.
6e00: 20 22 61 72 67 73 22 3a 20 5b 0a 20 20 20 20 20 "args": [.
6e10: 20 20 20 22 73 65 72 76 65 72 22 2c 0a 20 20 20 "server",.
6e20: 20 20 20 20 20 22 2d 2d 72 65 70 6f 6c 69 73 74 "--repolist
6e30: 22 2c 20 22 24 42 41 53 45 44 49 52 22 2c 0a 20 ", "$BASEDIR",.
6e40: 20 20 20 20 20 20 20 22 2d 2d 6e 6f 6a 61 69 6c "--nojail
6e50: 22 2c 0a 20 20 20 20 20 20 20 20 22 2d 2d 73 6b ",. "--sk
6e60: 69 6e 22 2c 20 22 64 61 72 6b 6d 6f 64 65 22 2c in", "darkmode",
6e70: 0a 20 20 20 20 20 20 20 20 22 2d 2d 65 78 74 72 . "--extr
6e80: 6f 6f 74 22 2c 20 22 24 42 41 53 45 44 49 52 2f oot", "$BASEDIR/
6e90: 6f 6c 6c 61 6d 61 2f 62 69 6e 22 2c 0a 20 20 20 ollama/bin",.
6ea0: 20 20 20 20 20 22 2d 2d 65 72 72 6f 72 6c 6f 67 "--errorlog
6eb0: 22 2c 20 22 24 42 41 53 45 44 49 52 2f 66 6f 73 ", "$BASEDIR/fos
6ec0: 73 69 6c 2e 65 72 72 2e 6c 6f 67 22 0a 20 20 20 sil.err.log".
6ed0: 20 20 20 5d 0a 20 20 20 20 7d 0a 20 20 7d 2c 0a ]. }. },.
6ee0: 20 20 22 2a 22 3a 20 7b 0a 20 20 20 20 22 66 6f "*": {. "fo
6ef0: 73 73 69 6c 5f 73 65 72 76 65 72 22 3a 20 7b 0a ssil_server": {.
6f00: 20 20 20 20 20 20 22 61 72 67 73 22 3a 20 5b 0a "args": [.
6f10: 20 20 20 20 20 20 20 20 22 73 65 72 76 65 72 22 "server"
6f20: 2c 0a 20 20 20 20 20 20 20 20 22 2d 2d 72 65 70 ,. "--rep
6f30: 6f 6c 69 73 74 22 2c 20 22 24 42 41 53 45 44 49 olist", "$BASEDI
6f40: 52 22 2c 0a 20 20 20 20 20 20 20 20 22 2d 2d 6e R",. "--n
6f50: 6f 6a 61 69 6c 22 2c 0a 20 20 20 20 20 20 20 20 ojail",.
6f60: 22 2d 2d 65 72 72 6f 72 6c 6f 67 22 2c 20 22 24 "--errorlog", "$
6f70: 42 41 53 45 44 49 52 2f 66 6f 73 73 69 6c 2e 65 BASEDIR/fossil.e
6f80: 72 72 2e 6c 6f 67 22 0a 20 20 20 20 20 20 5d 0a rr.log". ].
6f90: 20 20 20 20 7d 2c 0a 20 20 20 20 22 73 79 6e 63 },. "sync
6fa0: 22 3a 20 5b 0a 20 20 20 20 20 20 22 42 65 61 67 ": [. "Beag
6fb0: 6c 65 42 61 64 67 65 22 2c 0a 20 20 20 20 20 20 leBadge",.
6fc0: 22 61 72 6d 62 69 61 6e 2d 62 75 69 6c 64 22 2c "armbian-build",
6fd0: 0a 20 20 20 20 20 20 22 62 61 64 67 65 2d 6c 61 . "badge-la
6fe0: 75 6e 63 68 65 72 22 2c 0a 20 20 20 20 20 20 22 uncher",. "
6ff0: 62 61 74 74 6c 65 73 6e 61 6b 65 2d 72 75 6c 65 battlesnake-rule
7000: 73 22 2c 0a 20 20 20 20 20 20 22 62 62 2d 69 6d s",. "bb-im
7010: 61 67 65 72 2d 72 73 22 2c 0a 20 20 20 20 20 20 ager-rs",.
7020: 22 62 6c 61 62 6c 22 2c 0a 20 20 20 20 20 20 22 "blabl",. "
7030: 62 6f 61 72 64 2d 67 65 6e 65 72 61 74 6f 72 22 board-generator"
7040: 2c 0a 20 20 20 20 20 20 22 62 6f 6f 74 73 74 72 ,. "bootstr
7050: 61 70 2d 71 63 6f 77 32 22 2c 0a 20 20 20 20 20 ap-qcow2",.
7060: 20 22 63 6c 65 61 76 65 22 2c 0a 20 20 20 20 20 "cleave",.
7070: 20 22 63 72 79 73 74 61 6c 2d 62 6f 6f 74 73 74 "crystal-bootst
7080: 72 61 70 22 2c 0a 20 20 20 20 20 20 22 63 72 79 rap",. "cry
7090: 73 74 61 6c 2d 72 6f 62 6f 74 73 22 2c 0a 20 20 stal-robots",.
70a0: 20 20 20 20 22 63 72 79 73 74 61 6c 22 2c 0a 20 "crystal",.
70b0: 20 20 20 20 20 22 66 6f 73 73 69 6c 2d 73 63 6d "fossil-scm
70c0: 2e 6f 72 67 22 2c 0a 20 20 20 20 20 20 22 67 6c .org",. "gl
70d0: 69 6e 74 22 2c 0a 20 20 20 20 20 20 22 67 70 2d int",. "gp-
70e0: 63 72 79 73 74 61 6c 22 2c 0a 20 20 20 20 20 20 crystal",.
70f0: 22 69 6e 74 65 72 61 63 74 6f 72 22 2c 0a 20 20 "interactor",.
7100: 20 20 20 20 22 6a 6b 65 6d 62 65 64 64 65 64 2d "jkembedded-
7110: 61 75 64 69 6f 2d 62 6f 61 72 64 22 2c 0a 20 20 audio-board",.
7120: 20 20 20 20 22 6c 76 67 6c 2d 63 72 79 73 74 61 "lvgl-crysta
7130: 6c 22 2c 0a 20 20 20 20 20 20 22 6d 61 6b 65 2d l",. "make-
7140: 74 68 69 6e 67 73 2d 62 6f 6f 6b 22 2c 0a 20 20 things-book",.
7150: 20 20 20 20 22 6d 65 63 68 61 6e 69 63 61 6c 2d "mechanical-
7160: 74 75 72 6b 22 2c 0a 20 20 20 20 20 20 22 6d 69 turk",. "mi
7170: 63 72 6f 62 6c 6f 63 6b 73 2d 73 6d 61 6c 6c 76 croblocks-smallv
7180: 6d 22 2c 0a 20 20 20 20 20 20 22 6f 6c 6c 61 6d m",. "ollam
7190: 61 22 2c 0a 20 20 20 20 20 20 22 71 75 61 64 65 a",. "quade
71a0: 73 63 22 2c 0a 20 20 20 20 20 20 22 73 65 6d 61 sc",. "sema
71b0: 6e 74 69 63 2d 75 69 22 2c 0a 20 20 20 20 20 20 ntic-ui",.
71c0: 22 73 6f 63 69 61 6c 2d 62 61 64 67 65 22 2c 0a "social-badge",.
71d0: 20 20 20 20 20 20 22 73 74 6f 6e 65 22 2c 0a 20 "stone",.
71e0: 20 20 20 20 20 22 73 77 6b 2d 61 69 22 2c 0a 20 "swk-ai",.
71f0: 20 20 20 20 20 22 74 6f 75 72 6e 61 6d 65 6e 74 "tournament
7200: 2d 74 6f 6f 6c 22 2c 0a 20 20 20 20 20 20 22 76 -tool",. "v
7210: 73 78 2d 65 78 61 6d 70 6c 65 73 22 2c 0a 20 20 sx-examples",.
7220: 20 20 20 20 22 77 65 62 69 64 65 2d 61 67 65 6e "webide-agen
7230: 74 22 2c 0a 20 20 20 20 20 20 22 7a 65 70 74 6f t",. "zepto
7240: 22 0a 20 20 20 20 5d 0a 20 20 7d 2c 0a 20 20 22 ". ]. },. "
7250: 61 61 72 63 68 36 34 2d 31 22 3a 20 7b 0a 20 20 aarch64-1": {.
7260: 20 20 22 6f 63 78 22 3a 20 7b 0a 20 20 20 20 20 "ocx": {.
7270: 20 22 64 61 65 6d 6f 6e 5f 72 6f 6f 74 22 3a 20 "daemon_root":
7280: 22 2f 6f 70 74 2f 6f 63 78 22 2c 0a 20 20 20 20 "/opt/ocx",.
7290: 20 20 22 72 65 61 64 5f 77 72 69 74 65 22 3a 20 "read_write":
72a0: 5b 22 2f 64 61 74 61 22 5d 0a 20 20 20 20 7d 0a ["/data"]. }.
72b0: 20 20 7d 0a 7d 0a 00 00 00 00 00 00 00 00 00 00 }.}...........
72c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
72d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
72e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
72f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7310: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
73a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
73b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
73c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
73d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
73e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
73f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7400: 73 63 72 69 70 74 73 2d 66 6f 72 2d 72 65 76 69 scripts-for-revi
7410: 65 77 2d 33 2f 72 65 63 6f 72 64 2e 74 78 74 00 ew-3/record.txt.
7420: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7430: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7440: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7450: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7460: 00 00 00 00 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000
7470: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
7480: 30 30 32 30 30 33 37 00 31 35 32 37 30 36 36 34 0020037.15270664
7490: 36 31 33 00 30 31 35 35 32 31 00 20 30 00 00 00 613.015521. 0...
74a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
74b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
74c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
74d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
74e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
74f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7500: 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
7510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7520: 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
7530: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7590: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
75a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
75b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
75c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
75d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
75e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
75f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7600: 0a 3d 3d 20 62 75 69 6c 64 3a 20 73 74 61 72 74 .== build: start
7610: 2d 6f 63 78 2c 20 72 65 63 65 69 70 74 73 20 61 -ocx, receipts a
7620: 6e 64 20 6f 63 78 32 20 66 72 6f 6d 20 2f 76 61 nd ocx2 from /va
7630: 72 2f 6c 69 62 2f 6f 63 78 2f 61 67 65 6e 74 73 r/lib/ocx/agents
7640: 2f 6f 70 75 73 2d 6f 63 78 32 2f 70 72 6f 6a 65 /opus-ocx2/proje
7650: 63 74 73 2f 6f 6c 6c 61 6d 61 2f 62 32 64 65 38 cts/ollama/b2de8
7660: 62 30 63 32 63 36 37 30 30 65 62 35 63 36 38 36 b0c2c6700eb5c686
7670: 62 31 37 34 37 62 35 61 61 61 31 65 32 64 32 64 b1747b5aaa1e2d2d
7680: 30 31 33 37 30 61 63 35 35 66 32 65 35 61 31 35 01370ac55f2e5a15
7690: 31 61 36 37 65 30 33 62 34 38 61 2f 74 72 65 65 1a67e03b48a/tree
76a0: 38 0a 0a 3d 3d 20 73 65 72 76 65 64 20 72 65 70 8..== served rep
76b0: 6f 73 69 74 6f 72 79 3a 20 64 65 6d 6f 2e 66 6f ository: demo.fo
76c0: 73 73 69 6c 2c 20 75 73 65 72 73 2c 20 63 68 61 ssil, users, cha
76d0: 74 20 74 69 6d 65 6c 69 6e 65 0a 2d 72 77 2d 2d t timeline.-rw--
76e0: 2d 2d 2d 2d 2d 20 20 20 20 31 20 72 6f 6f 74 20 ----- 1 root
76f0: 20 20 20 20 72 6f 6f 74 20 20 20 20 20 20 20 20 root
7700: 32 31 37 30 38 38 20 4f 63 74 20 32 39 20 31 35 217088 Oct 29 15
7710: 3a 34 31 20 2f 74 6d 70 2f 73 41 2d 33 38 30 31 :41 /tmp/sA-3801
7720: 37 33 33 2f 66 6f 73 73 69 6c 2f 64 65 6d 6f 2e 733/fossil/demo.
7730: 66 6f 73 73 69 6c 0a 0a 3d 3d 20 72 65 63 65 69 fossil..== recei
7740: 70 74 20 73 65 72 76 69 63 65 2c 20 74 68 72 6f pt service, thro
7750: 75 67 68 20 74 68 65 20 6c 61 75 6e 63 68 65 72 ugh the launcher
7760: 27 73 20 72 65 63 65 69 70 74 73 20 70 6f 6c 69 's receipts poli
7770: 63 79 0a 74 6f 74 61 6c 20 30 0a 73 72 77 2d 2d cy.total 0.srw--
7780: 2d 2d 2d 2d 2d 20 20 20 20 31 20 72 6f 6f 74 20 ----- 1 root
7790: 20 20 20 20 72 6f 6f 74 20 20 20 20 20 20 20 20 root
77a0: 20 20 20 20 20 30 20 4f 63 74 20 32 39 20 31 35 0 Oct 29 15
77b0: 3a 34 31 20 72 65 63 65 69 70 74 73 2e 73 6f 63 :41 receipts.soc
77c0: 6b 0a 0a 3d 3d 20 46 6f 73 73 69 6c 20 73 65 72 k..== Fossil ser
77d0: 76 65 72 2c 20 69 74 73 20 65 78 74 72 6f 6f 74 ver, its extroot
77e0: 27 73 20 6f 63 78 32 2d 63 67 69 20 74 68 65 20 's ocx2-cgi the
77f0: 6c 61 75 6e 63 68 65 72 0a 0a 3d 3d 20 74 68 65 launcher..== the
7800: 20 64 61 65 6d 6f 6e 27 73 20 6e 6f 64 65 3a 20 daemon's node:
7810: 6e 6f 64 65 73 2e 6a 73 6f 6e 20 61 6e 64 20 63 nodes.json and c
7820: 72 65 64 65 6e 74 69 61 6c 73 0a 0a 3d 3d 20 63 redentials..== c
7830: 6f 6e 66 69 6e 65 64 20 64 61 65 6d 6f 6e 2c 20 onfined daemon,
7840: 74 68 72 6f 75 67 68 20 74 68 65 20 6c 61 75 6e through the laun
7850: 63 68 65 72 27 73 20 64 61 65 6d 6f 6e 20 70 6f cher's daemon po
7860: 6c 69 63 79 0a 7b 22 77 68 65 6e 22 3a 22 32 30 licy.{"when":"20
7870: 32 36 2d 31 30 2d 32 39 54 31 35 3a 34 32 3a 31 26-10-29T15:42:1
7880: 36 5a 22 2c 22 63 6c 6f 6e 65 22 3a 22 2f 74 6d 6Z","clone":"/tm
7890: 70 2f 73 41 2d 33 38 30 31 37 33 33 2f 64 61 65 p/sA-3801733/dae
78a0: 6d 6f 6e 2f 6e 6f 64 65 2f 63 6c 6f 6e 65 73 2f mon/node/clones/
78b0: 64 65 6d 6f 2e 66 6f 73 73 69 6c 22 2c 22 63 6f demo.fossil","co
78c0: 6d 70 6c 65 74 69 6f 6e 22 3a 31 2c 22 6e 65 77 mpletion":1,"new
78d0: 22 3a 30 2c 22 68 61 6e 64 65 64 22 3a 5b 5d 2c ":0,"handed":[],
78e0: 22 73 65 74 74 6c 65 64 22 3a 30 7d 0a 7b 22 77 "settled":0}.{"w
78f0: 68 65 6e 22 3a 22 32 30 32 36 2d 31 30 2d 32 39 hen":"2026-10-29
7900: 54 31 35 3a 34 32 3a 31 39 5a 22 2c 22 63 6c 6f T15:42:19Z","clo
7910: 6e 65 22 3a 22 2f 74 6d 70 2f 73 41 2d 33 38 30 ne":"/tmp/sA-380
7920: 31 37 33 33 2f 64 61 65 6d 6f 6e 2f 6e 6f 64 65 1733/daemon/node
7930: 2f 63 6c 6f 6e 65 73 2f 64 65 6d 6f 2e 66 6f 73 /clones/demo.fos
7940: 73 69 6c 22 2c 22 63 6f 6d 70 6c 65 74 69 6f 6e sil","completion
7950: 22 3a 31 2c 22 6e 65 77 22 3a 30 2c 22 68 61 6e ":1,"new":0,"han
7960: 64 65 64 22 3a 5b 5d 2c 22 73 65 74 74 6c 65 64 ded":[],"settled
7970: 22 3a 30 7d 0a 7b 22 77 68 65 6e 22 3a 22 32 30 ":0}.{"when":"20
7980: 32 36 2d 31 30 2d 32 39 54 31 35 3a 34 32 3a 32 26-10-29T15:42:2
7990: 32 5a 22 2c 22 63 6c 6f 6e 65 22 3a 22 2f 74 6d 2Z","clone":"/tm
79a0: 70 2f 73 41 2d 33 38 30 31 37 33 33 2f 64 61 65 p/sA-3801733/dae
79b0: 6d 6f 6e 2f 6e 6f 64 65 2f 63 6c 6f 6e 65 73 2f mon/node/clones/
79c0: 64 65 6d 6f 2e 66 6f 73 73 69 6c 22 2c 22 63 6f demo.fossil","co
79d0: 6d 70 6c 65 74 69 6f 6e 22 3a 31 2c 22 6e 65 77 mpletion":1,"new
79e0: 22 3a 30 2c 22 68 61 6e 64 65 64 22 3a 5b 5d 2c ":0,"handed":[],
79f0: 22 73 65 74 74 6c 65 64 22 3a 30 7d 0a 0a 3d 3d "settled":0}..==
7a00: 20 74 77 6f 20 72 75 6e 73 2c 20 70 6f 73 74 65 two runs, poste
7a10: 64 20 62 79 20 62 6f 73 73 20 28 73 65 74 75 70 d by boss (setup
7a20: 29 20 74 68 72 6f 75 67 68 20 46 6f 73 73 69 6c ) through Fossil
7a30: 27 73 20 66 6f 72 6d 0a 73 61 6e 64 62 6f 78 65 's form.sandboxe
7a40: 64 20 72 75 6e 20 62 62 31 61 61 36 37 66 39 65 d run bb1aa67f9e
7a50: 0a 75 6e 63 6f 6e 66 69 6e 65 64 20 72 75 6e 20 .unconfined run
7a60: 30 33 64 37 62 62 63 62 64 66 0a 0a 3d 3d 20 77 03d7bbcbdf..== w
7a70: 68 61 74 20 74 68 65 20 72 75 6e 73 20 70 6f 73 hat the runs pos
7a80: 74 65 64 20 28 73 74 61 72 74 65 64 2c 20 6b 65 ted (started, ke
7a90: 70 74 20 6c 6f 67 73 2c 20 65 6e 64 65 64 29 0a pt logs, ended).
7aa0: 27 62 62 31 61 61 36 37 66 39 65 27 2c 27 62 6f 'bb1aa67f9e','bo
7ab0: 73 73 27 2c 27 44 20 32 30 32 36 2d 31 30 2d 32 ss','D 2026-10-2
7ac0: 39 54 31 35 3a 34 32 3a 32 34 2e 33 37 32 20 48 9T15:42:24.372 H
7ad0: 20 73 61 6e 64 62 6f 78 65 64 5c 73 70 72 6f 62 sandboxed\sprob
7ae0: 65 20 4e 20 74 65 78 74 2f 78 2d 6d 61 72 6b 64 e N text/x-markd
7af0: 6f 77 6e 20 55 20 62 6f 73 73 20 57 20 31 30 30 own U boss W 100
7b00: 37 20 60 60 60 6a 73 6f 6e 20 7b 22 6f 63 78 22 7 ```json {"ocx"
7b10: 3a 20 31 2c 20 22 6b 69 6e 64 22 3a 20 22 72 75 : 1, "kind": "ru
7b20: 6e 22 2c 20 22 6e 6f 64 65 22 3a 20 22 64 65 6d n", "node": "dem
7b30: 6f 2d 6e 6f 64 65 22 2c 20 22 6f 62 6a 65 63 74 o-node", "object
7b40: 69 76 65 22 3a 20 22 50 72 6f 62 65 20 66 72 6f ive": "Probe fro
7b50: 6d 20 61 6e 20 61 67 65 6e 74 20 73 61 6e 64 62 m an agent sandb
7b60: 6f 78 2e 22 2c 20 22 77 6f 72 6b 73 70 61 63 65 ox.", "workspace
7b70: 22 3a 20 5b 7b 22 73 74 65 70 22 3a 20 22 64 69 ": [{"step": "di
7b80: 72 65 63 74 6f 72 79 22 2c 20 22 61 74 22 3a 20 rectory", "at":
7b90: 22 24 24 72 6f 6f 74 24 24 2f 24 24 75 73 65 72 "$$root$$/$$user
7ba0: 24 24 2f 70 72 6f 6a 65 63 74 73 2f 24 24 70 72 $$/projects/$$pr
7bb0: 6f 6a 65 63 74 24 24 2f 24 24 72 75 6e 24 24 22 oject$$/$$run$$"
7bc0: 7d 5d 2c 20 22 73 61 6e 64 62 6f 78 22 3a 20 7b }], "sandbox": {
7bd0: 22 75 69 64 22 3a 20 31 30 30 30 2c 20 22 67 69 "uid": 1000, "gi
7be0: 64 22 3a 20 31 30 30 30 2c 20 22 63 61 70 61 62 d": 1000, "capab
7bf0: 69 6c 69 74 69 65 73 22 3a 20 5b 5d 2c 20 22 6e ilities": [], "n
7c00: 65 74 77 6f 72 6b 22 3a 20 66 61 6c 73 65 2c 20 etwork": false,
7c10: 22 6f 77 6e 5f 73 65 73 73 69 6f 6e 22 3a 20 74 "own_session": t
7c20: 72 75 65 2c 20 22 65 6e 64 73 5f 77 69 74 68 5f rue, "ends_with_
7c30: 6e 6f 64 65 22 3a 20 74 72 75 65 2c 20 22 72 65 node": true, "re
7c40: 61 64 5f 6f 6e 6c 79 22 3a 20 5b 22 2f 75 73 72 ad_only": ["/usr
7c50: 22 2c 20 22 2f 62 69 6e 22 2c 20 22 2f 6c 69 62 ", "/bin", "/lib
7c60: 22 2c 20 22 2f 6c 69 62 36 34 22 5d 2c 20 22 72 ", "/lib64"], "r
7c70: 65 61 64 5f 77 72 69 74 65 22 3a 20 5b 22 24 24 ead_write": ["$$
7c80: 77 6f 72 6b 73 70 61 63 65 24 24 22 5d 2c 20 22 workspace$$"], "
7c90: 68 6f 6d 65 73 22 3a 20 5b 5d 2c 20 22 66 69 6c homes": [], "fil
7ca0: 65 73 22 3a 20 5b 5d 2c 20 22 70 72 6f 63 22 3a es": [], "proc":
7cb0: 20 22 2f 70 72 6f 63 22 2c 20 22 64 65 76 22 3a "/proc", "dev":
7cc0: 20 22 2f 64 65 76 22 2c 20 22 74 6d 70 22 3a 20 "/dev", "tmp":
7cd0: 22 2f 74 6d 70 22 7d 2c 20 22 6c 69 6d 69 74 73 "/tmp"}, "limits
7ce0: 22 3a 20 7b 22 77 61 6c 6c 22 3a 20 22 32 6d 22 ": {"wall": "2m"
7cf0: 7d 2c 20 22 70 72 6f 63 65 73 73 22 3a 20 7b 22 }, "process": {"
7d00: 75 73 65 72 22 3a 20 22 62 75 69 6c 64 27 0a 27 user": "build'.'
7d10: 30 33 64 37 62 62 63 62 64 66 27 2c 27 62 6f 73 03d7bbcbdf','bos
7d20: 73 27 2c 27 44 20 32 30 32 36 2d 31 30 2d 32 39 s','D 2026-10-29
7d30: 54 31 35 3a 34 32 3a 32 34 2e 34 37 39 20 48 20 T15:42:24.479 H
7d40: 75 6e 63 6f 6e 66 69 6e 65 64 5c 73 70 72 6f 62 unconfined\sprob
7d50: 65 20 4e 20 74 65 78 74 2f 78 2d 6d 61 72 6b 64 e N text/x-markd
7d60: 6f 77 6e 20 55 20 62 6f 73 73 20 57 20 36 34 32 own U boss W 642
7d70: 20 60 60 60 6a 73 6f 6e 20 7b 22 6f 63 78 22 3a ```json {"ocx":
7d80: 20 31 2c 20 22 6b 69 6e 64 22 3a 20 22 72 75 6e 1, "kind": "run
7d90: 22 2c 20 22 6e 6f 64 65 22 3a 20 22 64 65 6d 6f ", "node": "demo
7da0: 2d 6e 6f 64 65 22 2c 20 22 6f 62 6a 65 63 74 69 -node", "objecti
7db0: 76 65 22 3a 20 22 50 72 6f 62 65 20 66 72 6f 6d ve": "Probe from
7dc0: 20 74 68 65 20 64 61 65 6d 6f 6e 20 69 74 73 65 the daemon itse
7dd0: 6c 66 2c 20 75 6e 63 6f 6e 66 69 6e 65 64 20 62 lf, unconfined b
7de0: 79 20 61 6e 79 20 72 75 6e 20 73 61 6e 64 62 6f y any run sandbo
7df0: 78 2e 22 2c 20 22 70 72 6f 63 65 73 73 22 3a 20 x.", "process":
7e00: 7b 22 75 73 65 72 22 3a 20 22 62 75 69 6c 64 65 {"user": "builde
7e10: 72 22 2c 20 22 63 6f 6d 6d 61 6e 64 22 3a 20 5b r", "command": [
7e20: 22 2f 62 69 6e 2f 73 68 22 2c 20 22 2d 63 22 2c "/bin/sh", "-c",
7e30: 20 22 65 63 68 6f 20 75 69 64 3d 24 28 69 64 20 "echo uid=$(id
7e40: 2d 75 29 3b 20 66 6f 72 20 70 20 69 6e 20 2f 74 -u); for p in /t
7e50: 6d 70 2f 73 41 2d 33 38 30 31 37 33 33 2f 66 6f mp/sA-3801733/fo
7e60: 73 73 69 6c 20 2f 74 6d 70 2f 73 41 2d 33 38 30 ssil /tmp/sA-380
7e70: 31 37 33 33 2f 66 6f 73 73 69 6c 2f 64 65 6d 6f 1733/fossil/demo
7e80: 2e 66 6f 73 73 69 6c 3b 20 64 6f 20 5b 20 2d 65 .fossil; do [ -e
7e90: 20 24 70 20 5d 20 26 26 20 65 63 68 6f 20 56 49 $p ] && echo VI
7ea0: 53 49 42 4c 45 20 24 70 20 7c 7c 20 65 63 68 6f SIBLE $p || echo
7eb0: 20 61 62 73 65 6e 74 20 24 70 3b 20 64 6f 6e 65 absent $p; done
7ec0: 3b 20 68 65 61 64 20 2d 63 20 31 36 20 2f 74 6d ; head -c 16 /tm
7ed0: 70 2f 73 41 2d 33 38 30 31 37 33 33 2f 66 6f 73 p/sA-3801733/fos
7ee0: 73 69 6c 2f 64 65 6d 6f 2e 66 6f 73 73 69 6c 20 sil/demo.fossil
7ef0: 3e 2f 64 65 76 2f 6e 75 6c 6c 20 32 3e 26 31 20 >/dev/null 2>&1
7f00: 26 26 20 65 63 68 6f 20 52 45 41 44 2d 4f 4b 20 && echo READ-OK
7f10: 7c 7c 20 65 63 68 6f 20 72 65 61 64 2d 72 65 66 || echo read-ref
7f20: 75 73 65 64 3b 20 6e 3d 30 3b 20 66 6f 72 20 78 used; n=0; for x
7f30: 20 69 6e 20 2f 70 72 6f 63 2f 5b 30 2d 39 5d 2a in /proc/[0-9]*
7f40: 2f 72 6f 6f 74 2f 74 6d 70 2f 73 41 2d 33 38 30 /root/tmp/sA-380
7f50: 31 37 33 33 2f 66 6f 73 73 69 6c 2f 64 65 6d 6f 1733/fossil/demo
7f60: 2e 66 6f 73 73 69 6c 3b 20 64 6f 20 5b 20 2d 72 .fossil; do [ -r
7f70: 20 24 78 20 5d 20 26 26 20 6e 3d 24 27 0a 27 65 $x ] && n=$'.'e
7f80: 36 65 66 36 31 36 33 30 30 27 2c 27 64 65 6d 6f 6ef616300','demo
7f90: 2d 6e 6f 64 65 27 2c 27 44 20 32 30 32 36 2d 31 -node','D 2026-1
7fa0: 30 2d 32 39 54 31 35 3a 34 32 3a 32 35 2e 36 39 0-29T15:42:25.69
7fb0: 36 20 47 20 62 62 31 61 61 36 37 66 39 65 66 30 6 G bb1aa67f9ef0
7fc0: 35 63 31 61 33 64 66 64 38 35 37 36 61 34 37 38 5c1a3dfd8576a478
7fd0: 30 37 36 61 31 63 32 62 61 65 31 31 36 34 33 63 076a1c2bae11643c
7fe0: 31 36 62 37 63 34 33 65 38 33 35 36 62 31 33 64 16b7c43e8356b13d
7ff0: 31 61 63 63 20 49 20 62 62 31 61 61 36 37 66 39 1acc I bb1aa67f9
8000: 65 66 30 35 63 31 61 33 64 66 64 38 35 37 36 61 ef05c1a3dfd8576a
8010: 34 37 38 30 37 36 61 31 63 32 62 61 65 31 31 36 478076a1c2bae116
8020: 34 33 63 31 36 62 37 63 34 33 65 38 33 35 36 62 43c16b7c43e8356b
8030: 31 33 64 31 61 63 63 20 4e 20 74 65 78 74 2f 78 13d1acc N text/x
8040: 2d 6d 61 72 6b 64 6f 77 6e 20 55 20 64 65 6d 6f -markdown U demo
8050: 2d 6e 6f 64 65 20 57 20 36 38 37 20 60 60 60 6a -node W 687 ```j
8060: 73 6f 6e 20 7b 20 20 22 6f 63 78 22 3a 20 31 2c son { "ocx": 1,
8070: 20 20 22 6b 69 6e 64 22 3a 20 22 73 74 61 72 74 "kind": "start
8080: 65 64 22 2c 20 20 22 6e 6f 64 65 22 3a 20 22 64 ed", "node": "d
8090: 65 6d 6f 2d 6e 6f 64 65 22 2c 20 20 22 63 6c 6f emo-node", "clo
80a0: 6e 65 22 3a 20 22 37 31 38 34 36 64 30 33 39 37 ne": "71846d0397
80b0: 30 66 32 38 62 30 33 31 39 35 30 62 38 61 66 61 0f28b031950b8afa
80c0: 39 62 30 64 63 32 31 35 38 34 38 61 62 38 22 2c 9b0dc215848ab8",
80d0: 20 20 22 72 75 6e 22 3a 20 22 62 62 31 61 61 36 "run": "bb1aa6
80e0: 37 66 39 65 66 30 35 63 31 61 33 64 66 64 38 35 7f9ef05c1a3dfd85
80f0: 37 36 61 34 37 38 30 37 36 61 31 63 32 62 61 65 76a478076a1c2bae
8100: 31 31 36 34 33 63 31 36 62 37 63 34 33 65 38 33 11643c16b7c43e83
8110: 35 36 62 31 33 64 31 61 63 63 22 2c 20 20 22 76 56b13d1acc", "v
8120: 61 6c 75 65 73 22 3a 20 7b 20 20 20 22 72 6f 6f alues": { "roo
8130: 74 22 3a 20 22 2f 74 6d 70 2f 73 41 2d 33 38 30 t": "/tmp/sA-380
8140: 31 37 33 33 2f 64 61 65 6d 6f 6e 2f 61 67 65 6e 1733/daemon/agen
8150: 74 73 22 2c 20 20 20 22 70 72 6f 6a 65 63 74 22 ts", "project"
8160: 3a 20 22 64 65 6d 6f 22 2c 20 20 20 22 75 73 65 : "demo", "use
8170: 72 22 3a 20 22 62 75 69 6c 64 65 72 22 2c 20 20 r": "builder",
8180: 20 22 72 75 6e 22 3a 20 22 62 62 31 61 61 36 37 "run": "bb1aa67
8190: 66 39 65 66 30 35 63 31 61 33 64 66 64 38 35 37 f9ef05c1a3dfd857
81a0: 36 61 34 37 38 30 37 36 61 31 63 32 62 61 65 31 6a478076a1c2bae1
81b0: 31 36 34 33 63 31 36 62 37 63 34 33 65 38 33 35 1643c16b7c43e835
81c0: 36 62 31 33 64 31 61 63 63 22 2c 20 20 20 22 6e 6b13d1acc", "n
81d0: 6f 64 65 22 3a 20 22 64 65 6d 6f 2d 6e 6f 64 65 ode": "demo-node
81e0: 22 2c 20 20 20 22 73 65 72 76 65 72 22 3a 20 22 ", "server": "
81f0: 27 0a 27 61 61 30 37 65 35 30 38 32 38 27 2c 27 '.'aa07e50828','
8200: 64 65 6d 6f 2d 6e 6f 64 65 27 2c 27 44 20 32 30 demo-node','D 20
8210: 32 36 2d 31 30 2d 32 39 54 31 35 3a 34 32 3a 32 26-10-29T15:42:2
8220: 35 2e 38 39 31 20 47 20 62 62 31 61 61 36 37 66 5.891 G bb1aa67f
8230: 39 65 66 30 35 63 31 61 33 64 66 64 38 35 37 36 9ef05c1a3dfd8576
8240: 61 34 37 38 30 37 36 61 31 63 32 62 61 65 31 31 a478076a1c2bae11
8250: 36 34 33 63 31 36 62 37 63 34 33 65 38 33 35 36 643c16b7c43e8356
8260: 62 31 33 64 31 61 63 63 20 49 20 62 62 31 61 61 b13d1acc I bb1aa
8270: 36 37 66 39 65 66 30 35 63 31 61 33 64 66 64 38 67f9ef05c1a3dfd8
8280: 35 37 36 61 34 37 38 30 37 36 61 31 63 32 62 61 576a478076a1c2ba
8290: 65 31 31 36 34 33 63 31 36 62 37 63 34 33 65 38 e11643c16b7c43e8
82a0: 33 35 36 62 31 33 64 31 61 63 63 20 4e 20 74 65 356b13d1acc N te
82b0: 78 74 2f 78 2d 6d 61 72 6b 64 6f 77 6e 20 55 20 xt/x-markdown U
82c0: 64 65 6d 6f 2d 6e 6f 64 65 20 57 20 32 33 32 20 demo-node W 232
82d0: 54 68 65 20 70 72 6f 63 65 73 73 20 66 6f 72 20 The process for
82e0: 74 68 65 20 72 75 6e 20 62 62 31 61 61 36 37 66 the run bb1aa67f
82f0: 39 65 66 30 35 63 31 61 33 64 66 64 38 35 37 36 9ef05c1a3dfd8576
8300: 61 34 37 38 30 37 36 61 31 63 32 62 61 65 31 31 a478076a1c2bae11
8310: 36 34 33 63 31 36 62 37 63 34 33 65 38 33 35 36 643c16b7c43e8356
8320: 62 31 33 64 31 61 63 63 20 65 78 69 74 65 64 20 b13d1acc exited
8330: 30 2e 20 7e 7e 7e 7e 20 73 74 64 6f 75 74 20 75 0. ~~~~ stdout u
8340: 69 64 3d 31 30 30 30 20 61 62 73 65 6e 74 20 2f id=1000 absent /
8350: 74 6d 70 2f 73 41 2d 33 38 30 31 37 33 33 2f 66 tmp/sA-3801733/f
8360: 6f 73 73 69 6c 20 61 62 73 65 6e 74 20 2f 74 6d ossil absent /tm
8370: 70 2f 73 41 2d 33 38 30 31 37 33 33 2f 66 6f 73 p/sA-3801733/fos
8380: 73 69 6c 2f 64 65 6d 6f 2e 66 6f 73 73 69 6c 20 sil/demo.fossil
8390: 72 65 61 64 2d 72 65 66 75 73 65 64 20 70 72 6f read-refused pro
83a0: 63 2d 70 61 74 68 73 2d 72 65 61 64 61 62 6c 65 c-paths-readable
83b0: 3d 30 20 7e 7e 7e 7e 20 5a 20 33 30 63 32 33 35 =0 ~~~~ Z 30c235
83c0: 64 65 61 34 34 65 35 31 35 39 35 65 61 62 64 30 dea44e51595eabd0
83d0: 35 37 64 65 38 37 62 65 31 64 20 27 0a 27 39 62 57de87be1d '.'9b
83e0: 37 61 65 62 35 37 36 36 27 2c 27 64 65 6d 6f 2d 7aeb5766','demo-
83f0: 6e 6f 64 65 27 2c 27 44 20 32 30 32 36 2d 31 30 node','D 2026-10
8400: 2d 32 39 54 31 35 3a 34 32 3a 32 35 2e 39 30 31 -29T15:42:25.901
8410: 20 47 20 62 62 31 61 61 36 37 66 39 65 66 30 35 G bb1aa67f9ef05
8420: 63 31 61 33 64 66 64 38 35 37 36 61 34 37 38 30 c1a3dfd8576a4780
8430: 37 36 61 31 63 32 62 61 65 31 31 36 34 33 63 31 76a1c2bae11643c1
8440: 36 62 37 63 34 33 65 38 33 35 36 62 31 33 64 31 6b7c43e8356b13d1
8450: 61 63 63 20 49 20 62 62 31 61 61 36 37 66 39 65 acc I bb1aa67f9e
8460: 66 30 35 63 31 61 33 64 66 64 38 35 37 36 61 34 f05c1a3dfd8576a4
8470: 37 38 30 37 36 61 31 63 32 62 61 65 31 31 36 34 78076a1c2bae1164
8480: 33 63 31 36 62 37 63 34 33 65 38 33 35 36 62 31 3c16b7c43e8356b1
8490: 33 64 31 61 63 63 20 4e 20 74 65 78 74 2f 78 2d 3d1acc N text/x-
84a0: 6d 61 72 6b 64 6f 77 6e 20 55 20 64 65 6d 6f 2d markdown U demo-
84b0: 6e 6f 64 65 20 57 20 32 33 36 20 60 60 60 6a 73 node W 236 ```js
84c0: 6f 6e 20 7b 20 20 22 6f 63 78 22 3a 20 31 2c 20 on { "ocx": 1,
84d0: 20 22 6b 69 6e 64 22 3a 20 22 65 6e 64 65 64 22 "kind": "ended"
84e0: 2c 20 20 22 6e 6f 64 65 22 3a 20 22 64 65 6d 6f , "node": "demo
84f0: 2d 6e 6f 64 65 22 2c 20 20 22 63 6c 6f 6e 65 22 -node", "clone"
8500: 3a 20 22 37 31 38 34 36 64 30 33 39 37 30 66 32 : "71846d03970f2
8510: 38 62 30 33 31 39 35 30 62 38 61 66 61 39 62 30 8b031950b8afa9b0
8520: 64 63 32 31 35 38 34 38 61 62 38 22 2c 20 20 22 dc215848ab8", "
8530: 72 75 6e 22 3a 20 22 62 62 31 61 61 36 37 66 39 run": "bb1aa67f9
8540: 65 66 30 35 63 31 61 33 64 66 64 38 35 37 36 61 ef05c1a3dfd8576a
8550: 34 37 38 30 37 36 61 31 63 32 62 61 65 31 31 36 478076a1c2bae116
8560: 34 33 63 31 36 62 37 63 34 33 65 38 33 35 36 62 43c16b7c43e8356b
8570: 31 33 64 31 61 63 63 22 2c 20 20 22 6f 75 74 63 13d1acc", "outc
8580: 6f 6d 65 22 3a 20 22 65 78 69 74 65 64 22 2c 20 ome": "exited",
8590: 20 22 65 78 69 74 22 3a 20 30 20 7d 20 60 60 60 "exit": 0 } ```
85a0: 20 5a 20 33 61 62 31 34 62 34 65 31 65 64 61 62 Z 3ab14b4e1edab
85b0: 39 36 62 36 65 62 38 64 35 34 37 32 38 63 36 30 96b6eb8d54728c60
85c0: 32 65 64 20 27 0a 27 32 30 65 32 61 33 37 37 31 2ed '.'20e2a3771
85d0: 38 27 2c 27 64 65 6d 6f 2d 6e 6f 64 65 27 2c 27 8','demo-node','
85e0: 44 20 32 30 32 36 2d 31 30 2d 32 39 54 31 35 3a D 2026-10-29T15:
85f0: 34 32 3a 32 36 2e 30 37 35 20 47 20 30 33 64 37 42:26.075 G 03d7
8600: 62 62 63 62 64 66 38 32 63 31 62 66 66 65 31 37 bbcbdf82c1bffe17
8610: 39 63 31 33 65 30 63 61 62 36 33 63 33 36 31 36 9c13e0cab63c3616
8620: 32 30 35 39 31 35 64 34 62 35 62 36 65 35 30 34 205915d4b5b6e504
8630: 37 66 30 30 37 66 62 33 33 64 34 63 20 49 20 30 7f007fb33d4c I 0
8640: 33 64 37 62 62 63 62 64 66 38 32 63 31 62 66 66 3d7bbcbdf82c1bff
8650: 65 31 37 39 63 31 33 65 30 63 61 62 36 33 63 33 e179c13e0cab63c3
8660: 36 31 36 32 30 35 39 31 35 64 34 62 35 62 36 65 616205915d4b5b6e
8670: 35 30 34 37 66 30 30 37 66 62 33 33 64 34 63 20 5047f007fb33d4c
8680: 4e 20 74 65 78 74 2f 78 2d 6d 61 72 6b 64 6f 77 N text/x-markdow
8690: 6e 20 55 20 64 65 6d 6f 2d 6e 6f 64 65 20 57 20 n U demo-node W
86a0: 32 37 37 20 60 60 60 6a 73 6f 6e 20 7b 20 20 22 277 ```json { "
86b0: 6f 63 78 22 3a 20 31 2c 20 20 22 6b 69 6e 64 22 ocx": 1, "kind"
86c0: 3a 20 22 65 6e 64 65 64 22 2c 20 20 22 6e 6f 64 : "ended", "nod
86d0: 65 22 3a 20 22 64 65 6d 6f 2d 6e 6f 64 65 22 2c e": "demo-node",
86e0: 20 20 22 63 6c 6f 6e 65 22 3a 20 22 37 31 38 34 "clone": "7184
86f0: 36 64 30 33 39 37 30 66 32 38 62 30 33 31 39 35 6d03970f28b03195
8700: 30 62 38 61 66 61 39 62 30 64 63 32 31 35 38 34 0b8afa9b0dc21584
8710: 38 61 62 38 22 2c 20 20 22 72 75 6e 22 3a 20 22 8ab8", "run": "
8720: 30 33 64 37 62 62 63 62 64 66 38 32 63 31 62 66 03d7bbcbdf82c1bf
8730: 66 65 31 37 39 63 31 33 65 30 63 61 62 36 33 63 fe179c13e0cab63c
8740: 33 36 31 36 32 30 35 39 31 35 64 34 62 35 62 36 3616205915d4b5b6
8750: 65 35 30 34 37 66 30 30 37 66 62 33 33 64 34 63 e5047f007fb33d4c
8760: 22 2c 20 20 22 6f 75 74 63 6f 6d 65 22 3a 20 22 ", "outcome": "
8770: 72 65 66 75 73 65 64 22 2c 20 20 22 6e 6f 74 65 refused", "note
8780: 22 3a 20 22 74 68 69 73 20 6e 6f 64 65 20 72 75 ": "this node ru
8790: 6e 73 20 6f 6e 6c 79 20 73 61 6e 64 62 6f 78 65 ns only sandboxe
87a0: 64 20 70 72 6f 63 65 73 73 65 73 22 20 7d 20 60 d processes" } `
87b0: 60 60 20 5a 20 30 64 38 33 37 64 36 63 64 30 31 `` Z 0d837d6cd01
87c0: 37 62 62 31 61 31 38 30 31 64 64 62 63 62 38 32 7bb1a1801ddbcb82
87d0: 61 33 66 38 35 20 27 0a 0a 3d 3d 20 72 65 63 65 a3f85 '..== rece
87e0: 69 70 74 73 20 74 68 72 6f 75 67 68 20 74 68 65 ipts through the
87f0: 20 6c 61 75 6e 63 68 65 72 27 73 20 43 47 49 20 launcher's CGI
8800: 72 6f 75 74 65 2c 20 61 67 61 69 6e 73 74 20 46 route, against F
8810: 6f 73 73 69 6c 27 73 20 6f 77 6e 20 72 65 63 6f ossil's own reco
8820: 72 64 0a 62 6f 73 73 20 7b 22 61 72 74 69 66 61 rd.boss {"artifa
8830: 63 74 73 22 3a 20 5b 7b 22 61 72 74 69 66 61 63 cts": [{"artifac
8840: 74 22 3a 20 22 62 62 31 61 61 36 37 66 39 65 66 t": "bb1aa67f9ef
8850: 30 35 63 31 61 33 64 66 64 38 35 37 36 61 34 37 05c1a3dfd8576a47
8860: 38 30 37 36 61 31 63 32 62 61 65 31 31 36 34 33 8076a1c2bae11643
8870: 63 31 36 62 37 63 34 33 65 38 33 35 36 62 31 33 c16b7c43e8356b13
8880: 64 31 61 63 63 22 2c 20 22 72 65 63 65 69 76 65 d1acc", "receive
8890: 64 22 3a 20 74 72 75 65 2c 20 22 73 65 6e 64 65 d": true, "sende
88a0: 72 22 3a 20 22 62 6f 73 73 22 2c 20 22 63 61 70 r": "boss", "cap
88b0: 61 62 69 6c 69 74 69 65 73 22 3a 20 22 62 63 64 abilities": "bcd
88c0: 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 efghijklmnopqrst
88d0: 77 7a 32 33 34 35 36 37 41 44 22 2c 20 22 72 65 wz234567AD", "re
88e0: 63 65 69 70 74 22 3a 20 32 2c 20 22 72 69 64 22 ceipt": 2, "rid"
88f0: 3a 20 32 7d 5d 2c 20 22 75 73 65 72 22 3a 20 7b : 2}], "user": {
8900: 22 75 73 65 72 22 3a 20 22 64 65 6d 6f 2d 6e 6f "user": "demo-no
8910: 64 65 22 2c 20 22 63 61 70 61 62 69 6c 69 74 69 de", "capabiliti
8920: 65 73 22 3a 20 22 67 68 6a 6f 72 77 7a 34 43 22 es": "ghjorwz4C"
8930: 2c 20 22 77 69 6b 69 5f 6d 6f 64 65 72 61 74 65 , "wiki_moderate
8940: 64 22 3a 20 66 61 6c 73 65 2c 20 22 74 69 63 6b d": false, "tick
8950: 65 74 5f 6d 6f 64 65 72 61 74 65 64 22 3a 20 66 et_moderated": f
8960: 61 6c 73 65 7d 7d 0a 76 69 65 77 65 72 20 7b 22 alse}}.viewer {"
8970: 61 72 74 69 66 61 63 74 73 22 3a 20 5b 7b 22 61 artifacts": [{"a
8980: 72 74 69 66 61 63 74 22 3a 20 22 62 62 31 61 61 rtifact": "bb1aa
8990: 36 37 66 39 65 66 30 35 63 31 61 33 64 66 64 38 67f9ef05c1a3dfd8
89a0: 35 37 36 61 34 37 38 30 37 36 61 31 63 32 62 61 576a478076a1c2ba
89b0: 65 31 31 36 34 33 63 31 36 62 37 63 34 33 65 38 e11643c16b7c43e8
89c0: 33 35 36 62 31 33 64 31 61 63 63 22 2c 20 22 72 356b13d1acc", "r
89d0: 65 63 65 69 76 65 64 22 3a 20 74 72 75 65 2c 20 eceived": true,
89e0: 22 73 65 6e 64 65 72 22 3a 20 22 62 6f 73 73 22 "sender": "boss"
89f0: 2c 20 22 63 61 70 61 62 69 6c 69 74 69 65 73 22 , "capabilities"
8a00: 3a 20 22 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e : "bcdefghijklmn
8a10: 6f 70 71 72 73 74 77 7a 32 33 34 35 36 37 41 44 opqrstwz234567AD
8a20: 22 2c 20 22 72 65 63 65 69 70 74 22 3a 20 32 2c ", "receipt": 2,
8a30: 20 22 72 69 64 22 3a 20 32 7d 5d 2c 20 22 75 73 "rid": 2}], "us
8a40: 65 72 22 3a 20 7b 22 75 73 65 72 22 3a 20 22 64 er": {"user": "d
8a50: 65 6d 6f 2d 6e 6f 64 65 22 2c 20 22 63 61 70 61 emo-node", "capa
8a60: 62 69 6c 69 74 69 65 73 22 3a 20 22 67 68 6a 6f bilities": "ghjo
8a70: 72 77 7a 34 43 22 2c 20 22 77 69 6b 69 5f 6d 6f rwz4C", "wiki_mo
8a80: 64 65 72 61 74 65 64 22 3a 20 66 61 6c 73 65 2c derated": false,
8a90: 20 22 74 69 63 6b 65 74 5f 6d 6f 64 65 72 61 74 "ticket_moderat
8aa0: 65 64 22 3a 20 66 61 6c 73 65 7d 7d 0a 61 6e 6f ed": false}}.ano
8ab0: 6e 20 7b 22 61 72 74 69 66 61 63 74 73 22 3a 20 n {"artifacts":
8ac0: 5b 7b 22 61 72 74 69 66 61 63 74 22 3a 20 22 62 [{"artifact": "b
8ad0: 62 31 61 61 36 37 66 39 65 66 30 35 63 31 61 33 b1aa67f9ef05c1a3
8ae0: 64 66 64 38 35 37 36 61 34 37 38 30 37 36 61 31 dfd8576a478076a1
8af0: 63 32 62 61 65 31 31 36 34 33 63 31 36 62 37 63 c2bae11643c16b7c
8b00: 34 33 65 38 33 35 36 62 31 33 64 31 61 63 63 22 43e8356b13d1acc"
8b10: 2c 20 22 72 65 63 65 69 76 65 64 22 3a 20 74 72 , "received": tr
8b20: 75 65 2c 20 22 73 65 6e 64 65 72 22 3a 20 22 62 ue, "sender": "b
8b30: 6f 73 73 22 2c 20 22 63 61 70 61 62 69 6c 69 74 oss", "capabilit
8b40: 69 65 73 22 3a 20 22 62 63 64 65 66 67 68 69 6a ies": "bcdefghij
8b50: 6b 6c 6d 6e 6f 70 71 72 73 74 77 7a 32 33 34 35 klmnopqrstwz2345
8b60: 36 37 41 44 22 2c 20 22 72 65 63 65 69 70 74 22 67AD", "receipt"
8b70: 3a 20 32 2c 20 22 72 69 64 22 3a 20 32 7d 5d 2c : 2, "rid": 2}],
8b80: 20 22 75 73 65 72 22 3a 20 7b 22 75 73 65 72 22 "user": {"user"
8b90: 3a 20 22 64 65 6d 6f 2d 6e 6f 64 65 22 2c 20 22 : "demo-node", "
8ba0: 63 61 70 61 62 69 6c 69 74 69 65 73 22 3a 20 22 capabilities": "
8bb0: 67 68 6a 6f 72 77 7a 34 43 22 2c 20 22 77 69 6b ghjorwz4C", "wik
8bc0: 69 5f 6d 6f 64 65 72 61 74 65 64 22 3a 20 66 61 i_moderated": fa
8bd0: 6c 73 65 2c 20 22 74 69 63 6b 65 74 5f 6d 6f 64 lse, "ticket_mod
8be0: 65 72 61 74 65 64 22 3a 20 66 61 6c 73 65 7d 7d erated": false}}
8bf0: 0a 46 6f 73 73 69 6c 27 73 20 6f 77 6e 20 72 65 .Fossil's own re
8c00: 63 6f 72 64 3a 20 27 62 6f 73 73 27 2c 27 62 63 cord: 'boss','bc
8c10: 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 defghijklmnopqrs
8c20: 74 77 7a 32 33 34 35 36 37 41 44 27 2c 32 2c 32 twz234567AD',2,2
8c30: 0a 46 6f 73 73 69 6c 27 73 20 66 75 6c 6c 63 61 .Fossil's fullca
8c40: 70 28 64 65 6d 6f 2d 6e 6f 64 65 29 3a 20 27 67 p(demo-node): 'g
8c50: 68 6a 6f 72 77 7a 34 43 27 0a 0a 3d 3d 20 74 68 hjorwz4C'..== th
8c60: 65 20 63 6f 6e 73 6f 6c 65 2c 20 61 73 20 62 6f e console, as bo
8c70: 73 73 20 28 74 68 65 20 70 61 67 65 27 73 20 6f ss (the page's o
8c80: 74 68 65 72 20 70 61 74 68 73 20 73 74 69 6c 6c ther paths still
8c90: 20 70 61 73 73 20 74 68 72 6f 75 67 68 3a 20 45 pass through: E
8ca0: 36 29 0a 63 6f 6e 73 6f 6c 65 20 6f 6b 3a 20 54 6).console ok: T
8cb0: 72 75 65 20 7c 20 72 75 6e 73 20 72 75 6e 6e 69 rue | runs runni
8cc0: 6e 67 3a 20 30 20 7c 20 65 6e 64 65 64 3a 20 32 ng: 0 | ended: 2
8cd0: 0a 0a 3d 3d 20 77 72 69 74 65 73 20 66 72 6f 6d ..== writes from
8ce0: 20 74 68 65 20 72 65 63 65 69 70 74 20 73 65 72 the receipt ser
8cf0: 76 69 63 65 27 73 20 70 6f 6c 69 63 79 20 66 61 vice's policy fa
8d00: 69 6c 20 28 61 20 70 72 6f 62 65 20 69 6e 20 70 il (a probe in p
8d10: 6c 61 63 65 20 6f 66 20 72 65 63 65 69 70 74 73 lace of receipts
8d20: 29 0a 46 6f 73 73 69 6c 27 73 20 70 6f 72 74 20 ).Fossil's port
8d30: 35 37 31 32 31 20 61 6e 73 77 65 72 73 20 6f 6e 57121 answers on
8d40: 20 74 68 65 20 68 6f 73 74 3a 20 32 30 30 0a 47 the host: 200.G
8d50: 43 20 57 61 72 6e 69 6e 67 3a 20 43 6f 75 6c 64 C Warning: Could
8d60: 20 6e 6f 74 20 6f 70 65 6e 20 2f 70 72 6f 63 2f not open /proc/
8d70: 73 74 61 74 0a 6f 70 65 6e 20 74 68 65 20 72 65 stat.open the re
8d80: 70 6f 73 69 74 6f 72 79 20 66 6f 72 20 77 72 69 pository for wri
8d90: 74 69 6e 67 3a 20 72 65 66 75 73 65 64 20 28 46 ting: refused (F
8da0: 69 6c 65 3a 3a 45 72 72 6f 72 3a 20 45 72 72 6f ile::Error: Erro
8db0: 72 20 6f 70 65 6e 69 6e 67 20 66 69 6c 65 20 77 r opening file w
8dc0: 69 74 68 20 6d 6f 64 65 20 27 72 2b 27 3a 20 27 ith mode 'r+': '
8dd0: 2f 72 65 70 6f 73 69 74 6f 72 69 65 73 2f 64 65 /repositories/de
8de0: 6d 6f 2e 66 6f 73 73 69 6c 27 3a 20 52 65 61 64 mo.fossil': Read
8df0: 2d 6f 6e 6c 79 20 66 69 6c 65 20 73 79 73 74 65 -only file syste
8e00: 6d 29 0a 63 72 65 61 74 65 20 61 20 66 69 6c 65 m).create a file
8e10: 20 62 65 73 69 64 65 20 69 74 3a 20 72 65 66 75 beside it: refu
8e20: 73 65 64 20 28 46 69 6c 65 3a 3a 45 72 72 6f 72 sed (File::Error
8e30: 3a 20 45 72 72 6f 72 20 6f 70 65 6e 69 6e 67 20 : Error opening
8e40: 66 69 6c 65 20 77 69 74 68 20 6d 6f 64 65 20 27 file with mode '
8e50: 77 27 3a 20 27 2f 72 65 70 6f 73 69 74 6f 72 69 w': '/repositori
8e60: 65 73 2f 78 27 3a 20 52 65 61 64 2d 6f 6e 6c 79 es/x': Read-only
8e70: 20 66 69 6c 65 20 73 79 73 74 65 6d 29 0a 72 65 file system).re
8e80: 61 64 20 74 68 65 20 72 65 70 6f 73 69 74 6f 72 ad the repositor
8e90: 79 3a 20 72 65 61 64 20 6f 6b 20 28 61 6c 6c 6f y: read ok (allo
8ea0: 77 65 64 3a 20 72 65 61 64 2d 6f 6e 6c 79 29 0a wed: read-only).
8eb0: 72 65 61 63 68 20 46 6f 73 73 69 6c 27 73 20 70 reach Fossil's p
8ec0: 6f 72 74 3a 20 72 65 66 75 73 65 64 20 28 53 6f ort: refused (So
8ed0: 63 6b 65 74 3a 3a 43 6f 6e 6e 65 63 74 45 72 72 cket::ConnectErr
8ee0: 6f 72 3a 20 45 72 72 6f 72 20 63 6f 6e 6e 65 63 or: Error connec
8ef0: 74 69 6e 67 20 74 6f 20 27 31 32 37 2e 30 2e 30 ting to '127.0.0
8f00: 2e 31 3a 35 37 31 32 31 27 3a 20 43 6f 6e 6e 65 .1:57121': Conne
8f10: 63 74 69 6f 6e 20 72 65 66 75 73 65 64 29 0a 77 ction refused).w
8f20: 72 69 74 65 20 69 6e 20 69 74 73 20 73 6f 63 6b rite in its sock
8f30: 65 74 20 64 69 72 65 63 74 6f 72 79 3a 20 77 72 et directory: wr
8f40: 69 74 74 65 6e 20 28 61 6c 6c 6f 77 65 64 3a 20 itten (allowed:
8f50: 69 74 73 20 6f 6e 65 20 77 72 69 74 61 62 6c 65 its one writable
8f60: 20 70 6c 61 63 65 29 0a 0a 3d 3d 20 74 68 65 20 place)..== the
8f70: 64 61 65 6d 6f 6e 27 73 20 6f 77 6e 20 76 69 65 daemon's own vie
8f80: 77 3a 20 61 20 70 72 6f 62 65 20 69 6e 20 70 6c w: a probe in pl
8f90: 61 63 65 20 6f 66 20 69 74 73 20 70 72 6f 67 72 ace of its progr
8fa0: 61 6d 2c 20 73 74 61 72 74 65 64 20 74 68 72 6f am, started thro
8fb0: 75 67 68 20 74 68 65 20 73 61 6d 65 20 64 61 65 ugh the same dae
8fc0: 6d 6f 6e 20 70 6f 6c 69 63 79 0a 64 61 65 6d 6f mon policy.daemo
8fd0: 6e 20 70 72 6f 62 65 3a 20 75 69 64 3d 30 20 63 n probe: uid=0 c
8fe0: 61 70 73 3d 43 61 70 45 66 66 3a 20 30 30 30 30 aps=CapEff: 0000
8ff0: 30 31 66 66 66 66 66 66 66 66 66 66 0a 61 62 73 01ffffffffff.abs
9000: 65 6e 74 20 2f 74 6d 70 2f 73 41 2d 33 38 30 31 ent /tmp/sA-3801
9010: 37 33 33 2f 66 6f 73 73 69 6c 0a 61 62 73 65 6e 733/fossil.absen
9020: 74 20 2f 74 6d 70 2f 73 41 2d 33 38 30 31 37 33 t /tmp/sA-380173
9030: 33 2f 66 6f 73 73 69 6c 2f 64 65 6d 6f 2e 66 6f 3/fossil/demo.fo
9040: 73 73 69 6c 0a 70 72 6f 63 2d 70 61 74 68 73 2d ssil.proc-paths-
9050: 72 65 61 64 61 62 6c 65 3d 30 20 28 6f 74 68 65 readable=0 (othe
9060: 72 20 70 72 6f 63 65 73 73 65 73 20 6f 66 20 74 r processes of t
9070: 68 65 20 73 61 6d 65 20 61 63 63 6f 75 6e 74 3b he same account;
9080: 20 74 68 65 20 6c 69 76 65 20 64 61 65 6d 6f 6e the live daemon
9090: 20 68 61 73 20 61 6e 20 61 63 63 6f 75 6e 74 20 has an account
90a0: 6f 66 20 69 74 73 20 6f 77 6e 29 0a 61 67 65 6e of its own).agen
90b0: 74 20 73 61 6e 64 62 6f 78 20 69 6e 73 69 64 65 t sandbox inside
90c0: 3a 20 73 74 61 72 74 65 64 0a 0a 3d 3d 20 72 65 : started..== re
90d0: 76 69 65 77 20 74 65 73 74 3a 20 74 68 65 20 2f view test: the /
90e0: 72 65 63 65 69 70 74 20 61 6c 69 61 73 65 73 20 receipt aliases
90f0: 72 65 61 63 68 20 74 68 65 20 72 65 63 65 69 70 reach the receip
9100: 74 20 73 65 72 76 69 63 65 2c 20 6e 65 76 65 72 t service, never
9110: 20 74 68 65 20 70 61 73 73 74 68 72 6f 75 67 68 the passthrough
9120: 0a 2f 72 65 63 65 69 70 74 20 2d 3e 20 73 65 72 ./receipt -> ser
9130: 76 69 63 65 20 62 6f 73 73 0a 2f 72 65 63 65 69 vice boss./recei
9140: 70 74 2f 20 2d 3e 20 73 65 72 76 69 63 65 20 62 pt/ -> service b
9150: 6f 73 73 0a 2f 72 65 63 65 69 70 74 2f 78 20 2d oss./receipt/x -
9160: 3e 20 73 65 72 76 69 63 65 20 62 6f 73 73 0a 0a > service boss..
9170: 3d 3d 20 72 65 76 69 65 77 20 74 65 73 74 3a 20 == review test:
9180: 6f 6e 65 20 72 65 70 6f 73 69 74 6f 72 79 20 68 one repository h
9190: 65 6c 64 20 6c 6f 63 6b 65 64 20 77 68 69 6c 65 eld locked while
91a0: 20 61 6e 6f 74 68 65 72 20 69 73 20 61 73 6b 65 another is aske
91b0: 64 2c 20 73 74 72 61 69 67 68 74 20 61 74 20 74 d, straight at t
91c0: 68 65 20 73 65 72 76 69 63 65 27 73 20 73 6f 63 he service's soc
91d0: 6b 65 74 0a 64 65 6d 6f 20 28 6c 6f 63 6b 65 64 ket.demo (locked
91e0: 3d 54 72 75 65 29 3a 20 32 2e 30 32 20 73 20 20 =True): 2.02 s
91f0: 7b 22 75 6e 61 76 61 69 6c 61 62 6c 65 22 3a 22 {"unavailable":"
9200: 73 71 6c 69 74 65 20 65 72 72 6f 72 20 35 3a 20 sqlite error 5:
9210: 64 61 74 61 62 61 73 65 20 69 73 20 6c 6f 63 6b database is lock
9220: 65 64 22 2c 22 72 65 74 72 79 5f 61 66 74 65 72 ed","retry_after
9230: 22 3a 31 7d 0a 64 65 6d 6f 32 20 28 6c 6f 63 6b ":1}.demo2 (lock
9240: 65 64 3d 46 61 6c 73 65 29 3a 20 30 2e 30 20 73 ed=False): 0.0 s
9250: 20 20 7b 22 61 72 74 69 66 61 63 74 73 22 3a 5b {"artifacts":[
9260: 7b 22 61 72 74 69 66 61 63 74 22 3a 22 62 62 31 {"artifact":"bb1
9270: 61 61 36 37 66 39 65 66 30 35 63 31 61 33 64 66 aa67f9ef05c1a3df
9280: 64 38 35 37 36 61 34 37 38 30 37 36 61 31 63 32 d8576a478076a1c2
9290: 62 61 65 31 31 36 34 33 63 31 36 62 37 63 34 33 bae11643c16b7c43
92a0: 65 38 33 35 36 62 31 33 64 31 61 63 0a 0a 3d 3d e8356b13d1ac..==
92b0: 20 72 65 76 69 65 77 20 74 65 73 74 3a 20 69 6e review test: in
92c0: 73 69 64 65 20 74 68 65 20 43 47 49 20 73 61 6e side the CGI san
92d0: 64 62 6f 78 20 28 61 20 70 72 6f 62 65 20 69 6e dbox (a probe in
92e0: 20 70 6c 61 63 65 20 6f 66 20 74 68 65 20 72 65 place of the re
92f0: 6c 65 61 73 65 27 73 20 70 72 6f 67 72 61 6d 29 lease's program)
9300: 0a 61 72 67 73 3a 20 2d 2d 72 65 63 65 69 70 74 .args: --receipt
9310: 2d 66 64 20 33 0a 43 61 70 45 66 66 3a 20 30 30 -fd 3.CapEff: 00
9320: 30 30 30 30 30 30 30 30 30 30 30 30 30 30 0a 66 00000000000000.f
9330: 64 20 30 20 2d 3e 20 2f 64 65 76 2f 6e 75 6c 6c d 0 -> /dev/null
9340: 0a 66 64 20 31 20 2d 3e 20 70 69 70 65 3a 5b 39 .fd 1 -> pipe:[9
9350: 38 37 35 36 38 31 39 34 5d 0a 66 64 20 31 30 20 87568194].fd 10
9360: 2d 3e 20 2f 72 65 6c 65 61 73 65 2f 6f 63 78 32 -> /release/ocx2
9370: 2d 63 67 69 0a 66 64 20 32 20 2d 3e 20 70 69 70 -cgi.fd 2 -> pip
9380: 65 3a 5b 39 38 37 35 36 38 31 39 34 5d 0a 66 64 e:[987568194].fd
9390: 20 33 20 2d 3e 20 73 6f 63 6b 65 74 3a 5b 39 38 3 -> socket:[98
93a0: 37 35 36 37 34 33 34 5d 0a 66 64 20 34 20 2d 3e 7567434].fd 4 ->
93b0: 20 70 69 70 65 3a 5b 39 38 37 35 36 34 37 34 32 pipe:[987564742
93c0: 5d 0a 63 6f 6f 6b 69 65 3a 20 61 62 73 65 6e 74 ].cookie: absent
93d0: 20 6e 6f 6e 63 65 3a 20 61 62 73 65 6e 74 20 72 nonce: absent r
93e0: 65 70 6f 73 69 74 6f 72 79 3a 20 64 65 6d 6f 0a epository: demo.
93f0: 61 62 73 65 6e 74 20 2f 74 6d 70 2f 73 41 2d 33 absent /tmp/sA-3
9400: 38 30 31 37 33 33 2f 66 6f 73 73 69 6c 0a 61 62 801733/fossil.ab
9410: 73 65 6e 74 20 2f 74 6d 70 2f 73 41 2d 33 38 30 sent /tmp/sA-380
9420: 31 37 33 33 2f 66 6f 73 73 69 6c 2f 64 65 6d 6f 1733/fossil/demo
9430: 2e 66 6f 73 73 69 6c 0a 6e 65 74 77 6f 72 6b 3a .fossil.network:
9440: 20 30 30 30 0a 0a 3d 3d 20 72 65 76 69 65 77 20 000..== review
9450: 74 65 73 74 3a 20 61 20 72 65 63 65 69 70 74 20 test: a receipt
9460: 73 65 72 76 69 63 65 20 74 68 61 74 20 6c 69 73 service that lis
9470: 74 65 6e 73 20 62 75 74 20 6e 65 76 65 72 20 61 tens but never a
9480: 63 63 65 70 74 73 0a 73 74 61 74 75 73 20 35 30 ccepts.status 50
9490: 33 20 61 66 74 65 72 20 30 20 73 3a 20 7b 22 75 3 after 0 s: {"u
94a0: 6e 61 76 61 69 6c 61 62 6c 65 22 3a 22 72 65 63 navailable":"rec
94b0: 65 69 70 74 20 73 65 72 76 69 63 65 20 6e 6f 74 eipt service not
94c0: 20 61 6e 73 77 65 72 69 6e 67 22 7d 0a 0a 3d 3d answering"}..==
94d0: 20 72 6f 6c 6c 62 61 63 6b 20 70 6f 69 6e 74 3a rollback point:
94e0: 20 74 68 65 20 6c 61 75 6e 63 68 65 72 27 73 20 the launcher's
94f0: 43 47 49 20 6c 69 6e 6b 20 69 73 20 6f 6e 65 20 CGI link is one
9500: 66 69 6c 65 3b 20 74 68 65 20 70 72 65 76 69 6f file; the previo
9510: 75 73 20 70 61 67 65 20 69 73 20 74 68 65 20 72 us page is the r
9520: 65 6c 65 61 73 65 27 73 20 6f 77 6e 20 6f 63 78 elease's own ocx
9530: 32 0a 6c 72 77 78 72 77 78 72 77 78 20 20 20 20 2.lrwxrwxrwx
9540: 31 20 72 6f 6f 74 20 20 20 20 20 72 6f 6f 74 20 1 root root
9550: 20 20 20 20 20 20 20 20 20 20 31 34 32 20 4f 63 142 Oc
9560: 74 20 32 39 20 31 35 3a 34 31 20 2f 74 6d 70 2f t 29 15:41 /tmp/
9570: 73 41 2d 33 38 30 31 37 33 33 2f 65 78 74 2f 6f sA-3801733/ext/o
9580: 63 78 32 2d 63 67 69 20 2d 3e 20 2f 76 61 72 2f cx2-cgi -> /var/
9590: 6c 69 62 2f 6f 63 78 2f 61 67 65 6e 74 73 2f 6f lib/ocx/agents/o
95a0: 70 75 73 2d 6f 63 78 32 2f 70 72 6f 6a 65 63 74 pus-ocx2/project
95b0: 73 2f 6f 6c 6c 61 6d 61 2f 62 32 64 65 38 62 30 s/ollama/b2de8b0
95c0: 63 32 63 36 37 30 30 65 62 35 63 36 38 36 62 31 c2c6700eb5c686b1
95d0: 37 34 37 62 35 61 61 61 31 65 32 64 32 64 30 31 747b5aaa1e2d2d01
95e0: 33 37 30 61 63 35 35 66 32 65 35 61 31 35 31 61 370ac55f2e5a151a
95f0: 36 37 65 30 33 62 34 38 61 2f 77 6f 72 6b 2f 73 67e03b48a/work/s
9600: 74 61 67 65 41 2d 72 75 6e 31 30 2f 62 69 6e 2f tageA-run10/bin/
9610: 73 74 61 72 74 2d 6f 63 78 0a 64 6f 6e 65 0a 00 start-ocx.done..
9620: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9630: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9640: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9650: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9660: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9670: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9690: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
96a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
96b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
96c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
96d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
96e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
96f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9710: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9720: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9730: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9740: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9750: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9760: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9770: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
97a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
97b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
97c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
97d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
97e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
97f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9800: 73 63 72 69 70 74 73 2d 66 6f 72 2d 72 65 76 69 scripts-for-revi
9810: 65 77 2d 33 2f 73 68 61 72 64 2e 79 6d 6c 2e 64 ew-3/shard.yml.d
9820: 69 66 66 00 00 00 00 00 00 00 00 00 00 00 00 00 iff.............
9830: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9840: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9850: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9860: 00 00 00 00 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000
9870: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
9880: 30 30 30 31 32 33 30 00 31 35 32 37 30 36 36 34 0001230.15270664
9890: 36 31 33 00 30 31 36 32 32 37 00 20 30 00 00 00 613.016227. 0...
98a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
98b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
98c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
98d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
98e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
98f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9900: 00 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
9910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9920: 00 00 00 00 00 00 00 00 00 72 6f 6f 74 00 00 00 .........root...
9930: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9940: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9950: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9960: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9970: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9990: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
99a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
99b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
99c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
99d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
99e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
99f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9a00: 49 6e 64 65 78 3a 20 73 68 61 72 64 2e 79 6d 6c Index: shard.yml
9a10: 0a 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d .===============
9a20: 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d ================
9a30: 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d ================
9a40: 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d ================
9a50: 3d 3d 3d 0a 2d 2d 2d 20 73 68 61 72 64 2e 79 6d ===.--- shard.ym
9a60: 6c 0a 2b 2b 2b 20 73 68 61 72 64 2e 79 6d 6c 0a l.+++ shard.yml.
9a70: 40 40 20 2d 39 2c 31 33 20 2b 39 2c 31 32 20 40 @@ -9,13 +9,12 @
9a80: 40 0a 20 64 65 70 65 6e 64 65 6e 63 69 65 73 3a @. dependencies:
9a90: 0a 20 20 20 73 71 6c 69 74 65 33 3a 0a 20 20 20 . sqlite3:.
9aa0: 20 20 67 69 74 68 75 62 3a 20 63 72 79 73 74 61 github: crysta
9ab0: 6c 2d 6c 61 6e 67 2f 63 72 79 73 74 61 6c 2d 73 l-lang/crystal-s
9ac0: 71 6c 69 74 65 33 0a 20 20 20 20 20 76 65 72 73 qlite3. vers
9ad0: 69 6f 6e 3a 20 30 2e 32 33 2e 30 0a 20 0a 2d 23 ion: 0.23.0. .-#
9ae0: 20 54 68 65 20 62 75 69 6c 64 20 73 74 65 70 3a The build step:
9af0: 20 60 73 68 61 72 64 73 20 62 75 69 6c 64 60 20 `shards build`
9b00: 70 75 74 73 20 74 68 65 73 65 20 69 6e 20 62 69 puts these in bi
9b10: 6e 2f 2e 20 53 69 6e 63 65 20 73 6c 69 63 65 20 n/. Since slice
9b20: 31 20 4f 43 58 20 69 73 0a 2d 23 20 6f 6e 65 20 1 OCX is.-# one
9b30: 70 72 6f 67 72 61 6d 2c 20 6f 63 78 32 20 28 64 program, ocx2 (d
9b40: 6f 63 73 2f 73 6c 69 63 65 73 2e 6d 64 29 2e 20 ocs/slices.md).
9b50: 54 68 65 20 66 6f 75 72 20 62 75 69 6c 74 20 66 The four built f
9b60: 72 6f 6d 20 73 63 72 69 70 74 73 2f 20 61 72 65 rom scripts/ are
9b70: 20 74 68 65 20 6d 61 69 6e 74 61 69 6e 65 72 27 the maintainer'
9b80: 73 20 61 6e 64 20 72 75 6e 20 66 72 6f 6d 0a 2d s and run from.-
9b90: 23 20 61 20 63 68 65 63 6b 6f 75 74 27 73 20 62 # a checkout's b
9ba0: 69 6e 2f 2e 0a 2b 23 20 73 68 61 72 64 73 20 62 in/..+# shards b
9bb0: 75 69 6c 64 20 70 75 74 73 20 4f 43 58 20 61 6e uild puts OCX an
9bc0: 64 20 74 68 65 20 6d 61 69 6e 74 61 69 6e 65 72 d the maintainer
9bd0: 27 73 20 66 6f 75 72 20 68 6f 73 74 20 70 72 6f 's four host pro
9be0: 67 72 61 6d 73 20 69 6e 20 62 69 6e 2f 2e 0a 2b grams in bin/..+
9bf0: 23 20 43 6f 70 79 20 73 65 72 76 65 72 73 2e 6a # Copy servers.j
9c00: 73 6f 6e 20 62 65 73 69 64 65 20 74 68 65 20 62 son beside the b
9c10: 75 69 6c 74 20 70 72 6f 67 72 61 6d 73 20 77 68 uilt programs wh
9c20: 65 72 65 20 74 68 65 79 20 61 72 65 20 64 65 70 ere they are dep
9c30: 6c 6f 79 65 64 2e 0a 20 74 61 72 67 65 74 73 3a loyed.. targets:
9c40: 0a 20 20 20 6f 63 78 32 3a 0a 20 20 20 20 20 6d . ocx2:. m
9c50: 61 69 6e 3a 20 74 6f 6f 6c 73 2f 6f 63 78 32 2e ain: tools/ocx2.
9c60: 63 72 0a 20 20 20 73 74 61 72 74 2d 66 6f 73 73 cr. start-foss
9c70: 69 6c 3a 0a 20 20 20 20 20 6d 61 69 6e 3a 20 73 il:. main: s
9c80: 63 72 69 70 74 73 2f 73 74 61 72 74 2d 66 6f 73 cripts/start-fos
9c90: 73 69 6c 2e 63 72 0a 0a 00 00 00 00 00 00 00 00 sil.cr..........
9ca0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9cb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9cc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9cd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9ce0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9cf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9d10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9d20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9d30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9d40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9d50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9d60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9d70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9d90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9da0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9db0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9dc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9dd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9de0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9df0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9e00: 73 63 72 69 70 74 73 2d 66 6f 72 2d 72 65 76 69 scripts-for-revi
9e10: 65 77 2d 33 2f 52 45 41 44 4d 45 2e 74 78 74 00 ew-3/README.txt.
9e20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
9e30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
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 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000
9e70: 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000
9e80: 30 30 30 30 35 33 33 00 31 35 32 37 30 36 36 34 0000533.15270664
9e90: 36 31 33 00 30 31 35 31 37 37 00 20 30 00 00 00 613.015177. 0...
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 75 73 74 61 72 20 20 00 72 6f 6f 74 00 00 00 .ustar .root...
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 72 6f 6f 74 00 00 00 .........root...
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: 54 68 69 72 64 20 72 65 76 69 65 77 20 63 6f 70 Third review cop
a010: 79 2c 20 32 30 32 36 2d 31 30 2d 32 39 20 7e 31 y, 2026-10-29 ~1
a020: 35 3a 34 35 20 55 54 43 3a 20 61 6c 6c 20 66 6f 5:45 UTC: all fo
a030: 75 72 20 73 63 72 69 70 74 73 2f 20 66 69 6c 65 ur scripts/ file
a040: 73 20 6d 61 64 65 20 70 6c 61 69 6e 2c 20 73 65 s made plain, se
a050: 74 74 69 6e 67 73 20 69 6e 20 73 65 72 76 65 72 ttings in server
a060: 73 2e 6a 73 6f 6e 20 62 65 73 69 64 65 20 65 61 s.json beside ea
a070: 63 68 20 70 72 6f 67 72 61 6d 2e 20 4e 6f 74 20 ch program. Not
a080: 63 6f 6d 6d 69 74 74 65 64 2e 0a 52 65 61 64 69 committed..Readi
a090: 6e 67 20 6f 72 64 65 72 3a 20 73 65 72 76 65 72 ng order: server
a0a0: 73 2e 6a 73 6f 6e 20 28 65 76 65 72 79 20 73 65 s.json (every se
a0b0: 74 74 69 6e 67 20 70 65 72 20 73 65 72 76 65 72 tting per server
a0c0: 29 2c 20 74 68 65 6e 20 65 61 63 68 20 2e 63 72 ), then each .cr
a0d0: 20 66 72 6f 6d 20 69 74 73 20 74 6f 70 3a 20 77 from its top: w
a0e0: 68 61 74 20 69 74 20 64 6f 65 73 2c 20 74 68 65 hat it does, the
a0f0: 6e 20 69 74 73 20 73 74 65 70 73 2e 0a 72 65 63 n its steps..rec
a100: 6f 72 64 2e 74 78 74 3a 20 74 68 65 20 73 63 72 ord.txt: the scr
a110: 61 74 63 68 20 72 75 6e 20 61 67 61 69 6e 73 74 atch run against
a120: 20 74 68 65 73 65 20 66 69 6c 65 73 20 28 73 63 these files (sc
a130: 72 61 74 63 68 20 73 65 72 76 65 72 73 2e 6a 73 ratch servers.js
a140: 6f 6e 20 62 65 73 69 64 65 20 73 63 72 61 74 63 on beside scratc
a150: 68 20 63 6f 70 69 65 73 29 2e 0a 00 00 00 00 00 h copies).......
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: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a270: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a290: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a2a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a2b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a2c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a2d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a2e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a2f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a310: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a3a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a3b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a3c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a3d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a3e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a3f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a410: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a420: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a430: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a440: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a450: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a460: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a470: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a490: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a4a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a4b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a4c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a4d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a4e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a4f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a520: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a530: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a590: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a5a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a5b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a5c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a5d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a5e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a5f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................