Compare commits
2
Commits
8457372a0f
...
c17e8c7c5d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c17e8c7c5d | ||
|
|
fbb78d485f |
Generated
+65
-308
@@ -68,37 +68,24 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.11.0"
|
||||
version = "2.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
|
||||
checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.8.5"
|
||||
version = "1.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce"
|
||||
checksum = "6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
@@ -108,9 +95,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.62"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
|
||||
checksum = "f360145194ee8e21db5ee7f3fcd4fe52210864c75c985dae33218202c8bbe040"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex",
|
||||
@@ -118,15 +105,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.6.0"
|
||||
version = "4.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
|
||||
checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -134,9 +121,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.6.0"
|
||||
version = "4.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
|
||||
checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -146,9 +133,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.6.0"
|
||||
version = "4.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a"
|
||||
checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@@ -158,9 +145,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
||||
checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
@@ -176,9 +163,9 @@ checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
|
||||
checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -201,55 +188,38 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.3.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.9"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
|
||||
checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasip2",
|
||||
"wasip3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.3"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
||||
checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||
dependencies = [
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@@ -257,22 +227,14 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "id-arena"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.13.0"
|
||||
version = "2.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
||||
checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.16.1",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -281,23 +243,11 @@ version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
|
||||
|
||||
[[package]]
|
||||
name = "leb128fmt"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.183"
|
||||
version = "0.2.189"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
|
||||
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
@@ -305,18 +255,6 @@ version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.4"
|
||||
@@ -329,30 +267,20 @@ version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -365,9 +293,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.4"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
||||
checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
@@ -385,17 +313,11 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
@@ -403,51 +325,38 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.149"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98"
|
||||
checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
@@ -457,9 +366,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -487,9 +396,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
version = "1.1.6+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc"
|
||||
checksum = "920602543f0911ab71da12c50d59701da54c196d1a2bf5cb4b75667f137a406a"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde_core",
|
||||
@@ -502,39 +411,33 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
version = "1.1.1+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f"
|
||||
checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
version = "1.1.3+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011"
|
||||
checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56"
|
||||
dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_writer"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
version = "1.1.2+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed"
|
||||
checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
@@ -542,58 +445,6 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "wasip2"
|
||||
version = "1.0.2+wasi-0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasip3"
|
||||
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
|
||||
dependencies = [
|
||||
"leb128fmt",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"wasm-encoder",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"hashbrown 0.15.5",
|
||||
"indexmap",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
@@ -611,100 +462,6 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "1.0.1"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
|
||||
dependencies = [
|
||||
"wit-bindgen-rust-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck",
|
||||
"indexmap",
|
||||
"prettyplease",
|
||||
"syn",
|
||||
"wasm-metadata",
|
||||
"wit-bindgen-core",
|
||||
"wit-component",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wit-bindgen-core",
|
||||
"wit-bindgen-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder",
|
||||
"wasm-metadata",
|
||||
"wasmparser",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
"indexmap",
|
||||
"log",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||
checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81"
|
||||
|
||||
+2
-2
@@ -24,10 +24,10 @@ glob = "0.3"
|
||||
libc = "0.2"
|
||||
seccompiler = "0.5"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
shlex = "1.3.0"
|
||||
shlex = "2.0.1"
|
||||
syscalls = { version = "0.8", default-features = false, features = ["std"] }
|
||||
toml = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
shlex = "1.3.0"
|
||||
shlex = "2.0.1"
|
||||
tempfile = "3"
|
||||
|
||||
@@ -47,7 +47,9 @@ Settings can be stored in a TOML config file at `$XDG_CONFIG_HOME/agent-sandbox/
|
||||
ln -sf "$(pwd)/config-example.toml" "${XDG_CONFIG_HOME:-$HOME/.config}/agent-sandbox/config.toml"
|
||||
```
|
||||
|
||||
Top-level keys set defaults; `[profile.<name>]` sections define named presets selectable with `--profile <name>`. CLI flags always take highest precedence, followed by the active profile, then top-level defaults. When a profile is active, list-valued fields (`ro`, `rw`, `mask`, `env`, `unsetenv`, `bwrap-args`) append to the globals; scalar fields (modes, flags, `entrypoint`, `command`, `chdir`) replace them.
|
||||
Top-level keys set defaults; `[profile.<name>]` sections define named presets selectable with `--profile <name>`. CLI flags always take highest precedence, followed by the active profiles, then top-level defaults. When a profile is active, list-valued fields (`ro`, `rw`, `mask`, `env`, `unsetenv`, `bwrap-args`) append to the globals; scalar fields (modes, flags, `entrypoint`, `command`, `chdir`) replace them.
|
||||
|
||||
Several profiles combine: `--profile claude,gpu` (or `--profile claude --profile gpu`, or `profile = ["claude", "gpu"]` in the config) merges them left to right under the same rules, so a later profile's scalars win. A CLI `--profile` replaces the config's list rather than extending it. A profile's own `profile = ...` names its parents, which merge before it; a profile reached twice merges once.
|
||||
|
||||
```toml
|
||||
# Global defaults
|
||||
|
||||
+18
-10
@@ -1,10 +1,11 @@
|
||||
# Merge rules (apply to every layering below): scalars replace, vec fields
|
||||
# append, profiles merge by name.
|
||||
#
|
||||
# Layers, lowest precedence first: globals -> active profile (with its
|
||||
# ancestors folded in) -> CLI flags. `--profile` selects the active profile;
|
||||
# otherwise the top-level `profile` below is used. Profiles can themselves set
|
||||
# `profile = "parent"` to inherit from another profile.
|
||||
# Layers, lowest precedence first: globals -> active profiles (with their
|
||||
# ancestors folded in) -> CLI flags. `--profile a,b` selects the active
|
||||
# profiles, merged left to right; otherwise the top-level `profile` below is
|
||||
# used. Either form takes one name or a list. Profiles can themselves set
|
||||
# `profile = "parent"` (or a list) to inherit; a shared ancestor merges once.
|
||||
#
|
||||
# `extra-config` optionally points to a second file layered on top of this
|
||||
# one. Missing extra-config files are silently skipped; nesting is not
|
||||
@@ -24,10 +25,7 @@ whitelist = true
|
||||
ro = [
|
||||
"~/.config/agents",
|
||||
"~/.config/git",
|
||||
"/etc/alsa",
|
||||
"/run/user/1000/pulse",
|
||||
"/run/user/1000/pipewire-0",
|
||||
"~/.config/llama-server-api-key",
|
||||
"~/dev",
|
||||
# "/host/path:/sandbox/path", # SRC:DST -> mount host SRC at a different target
|
||||
]
|
||||
rw = [
|
||||
@@ -53,7 +51,7 @@ env = [
|
||||
# command = ["--model", "opus"] # default trailing args
|
||||
# bwrap-args = ["--tmpfs /opt/scratch"] # raw bwrap escape hatch
|
||||
|
||||
profile = "claude"
|
||||
profile = ["claude", "audio"]
|
||||
|
||||
[profiles.claude]
|
||||
ro = ["~/.local/share/claude-code"]
|
||||
@@ -61,7 +59,7 @@ rw = ["~/.config/claude"]
|
||||
entrypoint = ["claude", "--dangerously-skip-permissions"]
|
||||
|
||||
[profiles.codex]
|
||||
ro = ["~/.local/share/codex-cli"]
|
||||
ro = ["~/.local/share/codex-cli", "~/.agents"]
|
||||
rw = ["~/.config/codex"]
|
||||
entrypoint = ["codex", "--dangerously-bypass-approvals-and-sandbox"]
|
||||
|
||||
@@ -69,3 +67,13 @@ entrypoint = ["codex", "--dangerously-bypass-approvals-and-sandbox"]
|
||||
ro = ["~/.local/share/pi-agent"]
|
||||
rw = ["~/.config/pi"]
|
||||
entrypoint = ["pi"]
|
||||
|
||||
[profiles.audio]
|
||||
ro = ["/etc/alsa", "/run/user/1000/pulse", "/run/user/1000/pipewire-0"]
|
||||
|
||||
[profiles.gpu]
|
||||
bwrap-args = ["--dev-bind /dev/dri /dev/dri"]
|
||||
|
||||
[profiles.wayland]
|
||||
ro = ["/run/user/1000/wayland-0"]
|
||||
env = ["WAYLAND_DISPLAY=wayland-0"]
|
||||
|
||||
+9
-3
@@ -82,9 +82,15 @@ pub struct Args {
|
||||
#[arg(long, value_name = "PATH")]
|
||||
pub chdir: Option<PathBuf>,
|
||||
|
||||
/// Use a named profile from the config file
|
||||
#[arg(long, conflicts_with = "no_config")]
|
||||
pub profile: Option<String>,
|
||||
/// Use named profiles from the config file, merged in order (comma-separated, repeatable)
|
||||
#[arg(
|
||||
long,
|
||||
value_name = "NAME[,NAME...]",
|
||||
value_delimiter = ',',
|
||||
action = clap::ArgAction::Append,
|
||||
conflicts_with = "no_config"
|
||||
)]
|
||||
pub profile: Vec<String>,
|
||||
|
||||
/// Path to config file (default: $XDG_CONFIG_HOME/agent-sandbox/config.toml)
|
||||
#[arg(long = "config", value_name = "PATH", conflicts_with = "no_config")]
|
||||
|
||||
+96
-45
@@ -11,13 +11,13 @@ use crate::{BindSpec, EnvEntry, SandboxConfig, SandboxError, SandboxMode};
|
||||
pub fn build(args: Args, file_config: Option<FileConfig>) -> Result<SandboxConfig, SandboxError> {
|
||||
let (mut globals, mut profile) = match file_config {
|
||||
Some(c) => {
|
||||
let profile = c.resolve_profile(args.profile.as_deref())?;
|
||||
let profile = c.resolve_profile(&args.profile)?;
|
||||
(c.options, profile)
|
||||
}
|
||||
None => (
|
||||
Options::default(),
|
||||
ResolvedProfile {
|
||||
name: args.profile.clone(),
|
||||
name: join_profile_names(&args.profile),
|
||||
options: Options::default(),
|
||||
},
|
||||
),
|
||||
@@ -419,64 +419,89 @@ impl FileConfig {
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
fn resolve_profile(&self, selected: Option<&str>) -> Result<ResolvedProfile, SandboxError> {
|
||||
let Some(name) = selected
|
||||
.map(String::from)
|
||||
.or_else(|| self.options.profile.clone())
|
||||
else {
|
||||
return Ok(ResolvedProfile::default());
|
||||
fn resolve_profile(&self, selected: &[String]) -> Result<ResolvedProfile, SandboxError> {
|
||||
let names = if selected.is_empty() {
|
||||
self.options
|
||||
.profile
|
||||
.clone()
|
||||
.map(|p| p.0)
|
||||
.unwrap_or_default()
|
||||
} else {
|
||||
selected.to_vec()
|
||||
};
|
||||
let options = self.resolve_chain(&name)?;
|
||||
if names.is_empty() {
|
||||
return Ok(ResolvedProfile::default());
|
||||
}
|
||||
|
||||
let merged = self
|
||||
.linearize_profiles(&names)?
|
||||
.into_iter()
|
||||
.map(|name| self.profiles[&name].clone())
|
||||
.fold(Options::default(), |base, next| base.merge_with(next));
|
||||
|
||||
Ok(ResolvedProfile {
|
||||
name: Some(name),
|
||||
options,
|
||||
name: join_profile_names(&names),
|
||||
options: merged,
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_chain(&self, name: &str) -> Result<Options, SandboxError> {
|
||||
let chain = self.collect_chain(name)?;
|
||||
|
||||
let merged = chain
|
||||
.into_iter()
|
||||
.rev()
|
||||
.fold(Options::default(), |base, child| base.merge_with(child));
|
||||
|
||||
Ok(merged)
|
||||
fn linearize_profiles(&self, names: &[String]) -> Result<Vec<String>, SandboxError> {
|
||||
let mut walk = ProfileWalk::new(&self.profiles);
|
||||
for name in names {
|
||||
walk.visit(name)?;
|
||||
}
|
||||
Ok(walk.ordered)
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_chain(&self, name: &str) -> Result<Vec<Options>, SandboxError> {
|
||||
let mut visited: Vec<String> = Vec::new();
|
||||
let mut chain: Vec<Options> = Vec::new();
|
||||
let mut current = name.to_string();
|
||||
struct ProfileWalk<'a> {
|
||||
profiles: &'a HashMap<String, Options>,
|
||||
path: Vec<String>,
|
||||
ordered: Vec<String>,
|
||||
}
|
||||
|
||||
loop {
|
||||
if visited.iter().any(|seen| seen == ¤t) {
|
||||
visited.push(current);
|
||||
return Err(SandboxError::ProfileCycle(visited));
|
||||
}
|
||||
|
||||
let options = self
|
||||
.profiles
|
||||
.get(¤t)
|
||||
.cloned()
|
||||
.ok_or_else(|| SandboxError::ProfileNotFound(current.clone()))?;
|
||||
|
||||
visited.push(current);
|
||||
let parent = options.profile.clone();
|
||||
chain.push(options);
|
||||
|
||||
match parent {
|
||||
Some(p) => current = p,
|
||||
None => return Ok(chain),
|
||||
}
|
||||
impl<'a> ProfileWalk<'a> {
|
||||
fn new(profiles: &'a HashMap<String, Options>) -> Self {
|
||||
Self {
|
||||
profiles,
|
||||
path: Vec::new(),
|
||||
ordered: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit(&mut self, name: &str) -> Result<(), SandboxError> {
|
||||
if self.path.iter().any(|seen| seen == name) {
|
||||
self.path.push(name.to_string());
|
||||
return Err(SandboxError::ProfileCycle(self.path.clone()));
|
||||
}
|
||||
if self.ordered.iter().any(|done| done == name) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let options = self
|
||||
.profiles
|
||||
.get(name)
|
||||
.ok_or_else(|| SandboxError::ProfileNotFound(name.to_string()))?;
|
||||
|
||||
self.path.push(name.to_string());
|
||||
for parent in options.profile.iter().flat_map(|p| &p.0) {
|
||||
self.visit(parent)?;
|
||||
}
|
||||
self.path.pop();
|
||||
|
||||
self.ordered.push(name.to_string());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn join_profile_names(names: &[String]) -> Option<String> {
|
||||
(!names.is_empty()).then(|| names.join(","))
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Clone)]
|
||||
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
|
||||
pub struct Options {
|
||||
pub profile: Option<String>,
|
||||
pub profile: Option<ProfileNames>,
|
||||
pub blacklist: Option<bool>,
|
||||
pub whitelist: Option<bool>,
|
||||
pub hardened: Option<bool>,
|
||||
@@ -567,6 +592,32 @@ fn expand_and_require_absolute(path: &Path) -> Result<PathBuf, SandboxError> {
|
||||
Ok(expanded)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Debug, PartialEq)]
|
||||
#[serde(from = "OneOrMany")]
|
||||
pub struct ProfileNames(pub Vec<String>);
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum OneOrMany {
|
||||
One(String),
|
||||
Many(Vec<String>),
|
||||
}
|
||||
|
||||
impl From<OneOrMany> for ProfileNames {
|
||||
fn from(value: OneOrMany) -> Self {
|
||||
match value {
|
||||
OneOrMany::One(name) => Self(vec![name]),
|
||||
OneOrMany::Many(names) => Self(names),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for ProfileNames {
|
||||
fn from(name: &str) -> Self {
|
||||
Self(vec![name.to_string()])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum CommandValue {
|
||||
|
||||
+217
-20
@@ -1,5 +1,6 @@
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use clap::Parser;
|
||||
use tempfile::TempDir;
|
||||
|
||||
use super::*;
|
||||
@@ -122,7 +123,7 @@ fn build_profile_overrides_globals() {
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: Some("relaxed".into()),
|
||||
profile: vec!["relaxed".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
let config = build(args, Some(file_config)).unwrap();
|
||||
@@ -142,7 +143,7 @@ fn build_cli_flag_overrides_profile() {
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: Some("nonet".into()),
|
||||
profile: vec!["nonet".into()],
|
||||
unshare_net: true,
|
||||
..args_with_command()
|
||||
};
|
||||
@@ -267,7 +268,7 @@ fn build_cli_mode_overrides_profile() {
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: Some("wl".into()),
|
||||
profile: vec!["wl".into()],
|
||||
blacklist: true,
|
||||
..args_with_command()
|
||||
};
|
||||
@@ -292,7 +293,7 @@ fn build_rw_paths_accumulate() {
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: Some("extra".into()),
|
||||
profile: vec!["extra".into()],
|
||||
extra_rw: vec!["/var".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
@@ -316,7 +317,7 @@ fn build_command_from_profile() {
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: Some("test".into()),
|
||||
profile: vec!["test".into()],
|
||||
..Args::default()
|
||||
};
|
||||
let config = build(args, Some(file_config)).unwrap();
|
||||
@@ -337,7 +338,7 @@ fn build_cli_entrypoint_overrides_profile() {
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: Some("test".into()),
|
||||
profile: vec!["test".into()],
|
||||
entrypoint: Some("/usr/bin/true".into()),
|
||||
..Args::default()
|
||||
};
|
||||
@@ -455,7 +456,7 @@ fn build_cli_profile_overrides_top_level_profile() {
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: Some("other".into()),
|
||||
profile: vec!["other".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
let config = build(args, Some(file_config)).unwrap();
|
||||
@@ -480,7 +481,7 @@ fn build_missing_top_level_profile_errors() {
|
||||
#[test]
|
||||
fn build_missing_profile_errors() {
|
||||
let args = Args {
|
||||
profile: Some("nope".into()),
|
||||
profile: vec!["nope".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
assert!(matches!(
|
||||
@@ -516,7 +517,7 @@ fn inheritance_merges_parent_into_child() {
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: Some("child".into()),
|
||||
profile: vec!["child".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
let config = build(args, Some(file_config)).unwrap();
|
||||
@@ -565,7 +566,7 @@ fn inheritance_walks_multi_level_chain() {
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: Some("child".into()),
|
||||
profile: vec!["child".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
let config = build(args, Some(file_config)).unwrap();
|
||||
@@ -632,7 +633,7 @@ fn inheritance_cycle_errors() {
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: Some("a".into()),
|
||||
profile: vec!["a".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
assert!(matches!(
|
||||
@@ -654,7 +655,7 @@ fn missing_parent_profile_errors() {
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: Some("child".into()),
|
||||
profile: vec!["child".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
assert!(matches!(
|
||||
@@ -695,7 +696,7 @@ fn inheritance_chain_spans_extra_config() {
|
||||
|
||||
let file_config = FileConfig::load(&base_path).unwrap();
|
||||
let args = Args {
|
||||
profile: Some("child".into()),
|
||||
profile: vec!["child".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
let config = build(args, Some(file_config)).unwrap();
|
||||
@@ -940,7 +941,7 @@ fn build_env_accumulates_disjoint_keys() {
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: Some("p".into()),
|
||||
profile: vec!["p".into()],
|
||||
env: vec!["D".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
@@ -973,7 +974,7 @@ fn build_env_later_tier_overrides_earlier() {
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: Some("p".into()),
|
||||
profile: vec!["p".into()],
|
||||
env: vec!["A=cli".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
@@ -1058,7 +1059,7 @@ fn build_unsetenv_accumulates() {
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: Some("p".into()),
|
||||
profile: vec!["p".into()],
|
||||
unsetenv: vec!["C".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
@@ -1184,11 +1185,11 @@ fn persistent_tmp_uses_leaf_profile_name() {
|
||||
};
|
||||
|
||||
let leaf_args = Args {
|
||||
profile: Some("leaf".into()),
|
||||
profile: vec!["leaf".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
let parent_args = Args {
|
||||
profile: Some("leaf".into()),
|
||||
profile: vec!["leaf".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
// Same profile selected: same key.
|
||||
@@ -1211,7 +1212,7 @@ fn persistent_tmp_uses_leaf_profile_name() {
|
||||
.unwrap()
|
||||
.persistent_tmp = Some(true);
|
||||
let parent_direct = Args {
|
||||
profile: Some("parent".into()),
|
||||
profile: vec!["parent".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
let key3 = build(parent_direct, Some(file_config2))
|
||||
@@ -1246,7 +1247,7 @@ fn build_mask_accumulates() {
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: Some("extra".into()),
|
||||
profile: vec!["extra".into()],
|
||||
mask: vec![PathBuf::from("/tmp/c")],
|
||||
..args_with_command()
|
||||
};
|
||||
@@ -1619,6 +1620,202 @@ fn load_extra_relative_path_rejected() {
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cli_profile_splits_on_commas() {
|
||||
let args = Args::try_parse_from(["agent-sandbox", "--profile", "claude,gpu"]).unwrap();
|
||||
assert_eq!(args.profile, vec!["claude", "gpu"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cli_repeated_profiles_concatenate_in_order() {
|
||||
let args = Args::try_parse_from([
|
||||
"agent-sandbox",
|
||||
"--profile",
|
||||
"claude",
|
||||
"--profile=gpu,wayland",
|
||||
])
|
||||
.unwrap();
|
||||
assert_eq!(args.profile, vec!["claude", "gpu", "wayland"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_profile_accepts_a_list() {
|
||||
let config: FileConfig = toml::from_str(r#"profile = ["claude", "gpu"]"#).unwrap();
|
||||
assert_eq!(
|
||||
config.options.profile,
|
||||
Some(ProfileNames(vec!["claude".into(), "gpu".into()]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_profile_accepts_a_single_name() {
|
||||
let config: FileConfig = toml::from_str(r#"profile = "claude""#).unwrap();
|
||||
assert_eq!(config.options.profile, Some("claude".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_merges_selected_profiles_in_order() {
|
||||
let args = Args {
|
||||
profile: vec!["claude".into(), "gpu".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
let config = build(args, Some(claude_and_gpu_profiles())).unwrap();
|
||||
|
||||
assert!(!config.hardened);
|
||||
assert!(config.unshare_net);
|
||||
assert_eq!(
|
||||
config.env,
|
||||
vec![
|
||||
EnvEntry::Set("FROM_CLAUDE".into(), "1".into()),
|
||||
EnvEntry::Set("FROM_GPU".into(), "1".into()),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_merges_top_level_profile_list() {
|
||||
let file_config = FileConfig {
|
||||
options: Options {
|
||||
profile: Some(ProfileNames(vec!["claude".into(), "gpu".into()])),
|
||||
..Options::default()
|
||||
},
|
||||
..claude_and_gpu_profiles()
|
||||
};
|
||||
let config = build(args_with_command(), Some(file_config)).unwrap();
|
||||
|
||||
assert!(!config.hardened);
|
||||
assert!(config.unshare_net);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_cli_profile_list_replaces_top_level_list() {
|
||||
let file_config = FileConfig {
|
||||
options: Options {
|
||||
profile: Some(ProfileNames(vec!["claude".into(), "gpu".into()])),
|
||||
..Options::default()
|
||||
},
|
||||
..claude_and_gpu_profiles()
|
||||
};
|
||||
let args = Args {
|
||||
profile: vec!["gpu".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
let config = build(args, Some(file_config)).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
config.env,
|
||||
vec![EnvEntry::Set("FROM_GPU".into(), "1".into())]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_shared_parent_merges_once() {
|
||||
let file_config = FileConfig {
|
||||
profiles: HashMap::from([
|
||||
(
|
||||
"base".into(),
|
||||
Options {
|
||||
ro: vec!["/etc".into()],
|
||||
..Options::default()
|
||||
},
|
||||
),
|
||||
(
|
||||
"claude".into(),
|
||||
Options {
|
||||
profile: Some("base".into()),
|
||||
..Options::default()
|
||||
},
|
||||
),
|
||||
(
|
||||
"gpu".into(),
|
||||
Options {
|
||||
profile: Some("base".into()),
|
||||
..Options::default()
|
||||
},
|
||||
),
|
||||
]),
|
||||
..FileConfig::default()
|
||||
};
|
||||
let args = Args {
|
||||
profile: vec!["claude".into(), "gpu".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
let config = build(args, Some(file_config)).unwrap();
|
||||
|
||||
assert_eq!(config.extra_ro, vec![same_bind(Path::new("/etc"))]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_profile_inherits_from_a_parent_list() {
|
||||
let mut file_config = claude_and_gpu_profiles();
|
||||
file_config.profiles.insert(
|
||||
"both".into(),
|
||||
Options {
|
||||
profile: Some(ProfileNames(vec!["claude".into(), "gpu".into()])),
|
||||
..Options::default()
|
||||
},
|
||||
);
|
||||
let args = Args {
|
||||
profile: vec!["both".into()],
|
||||
..args_with_command()
|
||||
};
|
||||
let config = build(args, Some(file_config)).unwrap();
|
||||
|
||||
assert!(!config.hardened);
|
||||
assert!(config.unshare_net);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn persistent_tmp_key_differs_per_profile_list() {
|
||||
let file_config = FileConfig {
|
||||
options: Options {
|
||||
persistent_tmp: Some(true),
|
||||
..Options::default()
|
||||
},
|
||||
..claude_and_gpu_profiles()
|
||||
};
|
||||
let key_for = |profiles: Vec<String>| {
|
||||
let args = Args {
|
||||
profile: profiles,
|
||||
..args_with_command()
|
||||
};
|
||||
build(args, Some(clone_file_config(&file_config)))
|
||||
.unwrap()
|
||||
.persistent_tmp_key
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
assert_ne!(
|
||||
key_for(vec!["claude".into()]),
|
||||
key_for(vec!["claude".into(), "gpu".into()])
|
||||
);
|
||||
}
|
||||
|
||||
fn claude_and_gpu_profiles() -> FileConfig {
|
||||
FileConfig {
|
||||
profiles: HashMap::from([
|
||||
(
|
||||
"claude".into(),
|
||||
Options {
|
||||
hardened: Some(true),
|
||||
env: vec!["FROM_CLAUDE=1".into()],
|
||||
..Options::default()
|
||||
},
|
||||
),
|
||||
(
|
||||
"gpu".into(),
|
||||
Options {
|
||||
hardened: Some(false),
|
||||
unshare_net: Some(true),
|
||||
env: vec!["FROM_GPU=1".into()],
|
||||
..Options::default()
|
||||
},
|
||||
),
|
||||
]),
|
||||
..FileConfig::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_paths(actual: &[String], expected: &[&str]) {
|
||||
let expected: Vec<String> = expected.iter().map(|s| s.to_string()).collect();
|
||||
assert_eq!(actual, &expected);
|
||||
|
||||
Reference in New Issue
Block a user