summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/arti/Cargo.toml2
-rw-r--r--crates/arti/tests/README.md40
-rw-r--r--crates/arti/tests/cli_tests.rs42
-rw-r--r--crates/arti/tests/testcases/hsc-feature-missing/hsc.in/hsc.toml11
-rw-r--r--crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/keystore/client/mnyizjj7m3hpcr7i5afph3zt7maa65johyu2ruis6z7cmnjmaj3h6tad/ks_hsc_desc_enc.x25519_private7
-rw-r--r--crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/state/circuit_timeouts.json5
-rw-r--r--crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/state/guards.json14
-rw-r--r--crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/state/state.lock0
-rw-r--r--crates/arti/tests/testcases/hsc-feature-missing/hsc.md9
-rw-r--r--crates/arti/tests/testcases/hsc/conf/hsc.toml11
-rw-r--r--crates/arti/tests/testcases/hsc/get-key-error.stderr1
-rw-r--r--crates/arti/tests/testcases/hsc/get-key-error.stdout0
-rw-r--r--crates/arti/tests/testcases/hsc/get-key-error.toml3
-rw-r--r--crates/arti/tests/testcases/hsc/help.stderr0
-rw-r--r--crates/arti/tests/testcases/hsc/help.stdout18
-rw-r--r--crates/arti/tests/testcases/hsc/help.toml3
-rw-r--r--crates/arti/tests/testcases/hsc/hsc.in/hsc.toml11
-rw-r--r--crates/arti/tests/testcases/hsc/hsc.in/local/keystore/client/mnyizjj7m3hpcr7i5afph3zt7maa65johyu2ruis6z7cmnjmaj3h6tad/ks_hsc_desc_enc.x25519_private7
-rw-r--r--crates/arti/tests/testcases/hsc/hsc.in/local/state/circuit_timeouts.json5
-rw-r--r--crates/arti/tests/testcases/hsc/hsc.in/local/state/guards.json14
-rw-r--r--crates/arti/tests/testcases/hsc/hsc.in/local/state/state.lock0
-rw-r--r--crates/arti/tests/testcases/hsc/hsc.md12
-rw-r--r--crates/arti/tests/testcases/hss-feature-missing/hss.in/hss.toml13
-rw-r--r--crates/arti/tests/testcases/hss-feature-missing/hss.in/local/keystore/hss/acutus-cepa/ks_hs_id.ed25519_expanded_private8
-rw-r--r--crates/arti/tests/testcases/hss-feature-missing/hss.md9
-rw-r--r--crates/arti/tests/testcases/hss/help.stderr0
-rw-r--r--crates/arti/tests/testcases/hss/help.stdout18
-rw-r--r--crates/arti/tests/testcases/hss/help.toml3
-rw-r--r--crates/arti/tests/testcases/hss/hss.in/hss.toml17
-rw-r--r--crates/arti/tests/testcases/hss/hss.in/local/keystore/hss/acutus-cepa/ks_hs_id.ed25519_expanded_private8
-rw-r--r--crates/arti/tests/testcases/hss/hss.md14
31 files changed, 305 insertions, 0 deletions
diff --git a/crates/arti/Cargo.toml b/crates/arti/Cargo.toml
index 7b4e9de9d..8c54376dc 100644
--- a/crates/arti/Cargo.toml
+++ b/crates/arti/Cargo.toml
@@ -140,6 +140,8 @@ derive_more = "0.99.3"
itertools = "0.13.0"
regex = { version = "1", default-features = false, features = ["std"] }
serde_json = "1.0.50"
+tempfile = "3"
+trycmd = "0.15.4"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.8", features = ["winerror"] }
diff --git a/crates/arti/tests/README.md b/crates/arti/tests/README.md
new file mode 100644
index 000000000..2259c4d28
--- /dev/null
+++ b/crates/arti/tests/README.md
@@ -0,0 +1,40 @@
+# Arti CLI tests
+
+This is a [`trycmd`]-based test suite for the arti CLI.
+
+Each testable subcommand has a corresponding directory in `testdata`:
+```
+tests
+├── cli_tests.rs # The test runner
+├── README.md
+└── testcases
+ ├── hsc
+ │   ├── help.stderr # expected stderr for the "help" test
+ │   ├── help.stdout # expected stdout for the "help" test
+ │   ├── help.toml # hsc "help" test
+ │   ├── hsc.in # test inputs and CWD
+ │   └── hsc.md # multiple hsc tests
+ ├── hss # hss subcommand tests
+ │   ├── hss.in # test inputs and CWD
+ │   └── hss.md # multiple hss tests
+ └── ...
+```
+
+Each feature-dependent subcommand has a corresponding `<subcmd>-feature-missing`
+test case, which tests that we output a hint about recompiling arti with the
+necessary features (the feature-dependent tests are currently all skipped,
+because we don't yet print helpful messages in such cases. See #1487).
+
+The tests can be written as [`*.trycmd`/`*.md` files], or in [`toml` format].
+The `*md`-based tests can double as documentation, so they are often preferable
+over the `toml` ones.
+
+See the [`trycmd`] docs for more information.
+
+### Debugging
+
+You can pass `-F trycmd/debug` to `cargo test` to debug `trycmd`'s behavior.`
+
+[`trycmd`]: https://docs.rs/trycmd/latest/trycmd/
+[`*.trycmd`/`*.md` files]: https://docs.rs/trycmd/latest/trycmd/#trycmd
+[`toml` format]: https://docs.rs/trycmd/latest/trycmd/#toml
diff --git a/crates/arti/tests/cli_tests.rs b/crates/arti/tests/cli_tests.rs
new file mode 100644
index 000000000..e473d2fad
--- /dev/null
+++ b/crates/arti/tests/cli_tests.rs
@@ -0,0 +1,42 @@
+#![doc = include_str!("../README.md")]
+
+#[test]
+fn cli_tests() {
+ let t = trycmd::TestCases::new();
+ let dir = tempfile::TempDir::new().unwrap();
+ t.env("HOME", dir.path().to_str().unwrap());
+
+ cfg_if::cfg_if! {
+ if #[cfg(feature = "onion-service-service")] {
+ t.case("tests/testcases/hss/*.toml");
+ t.case("tests/testcases/hss/*.md");
+ } else {
+ // This is not yet implemented, see #1487
+ t.skip("tests/testcases/hss-feature-missing/*.toml");
+ t.skip("tests/testcases/hss-feature-missing/*.md");
+ }
+ }
+
+ cfg_if::cfg_if! {
+ if #[cfg(all(feature = "onion-service-client", feature = "experimental-api", feature = "keymgr"))] {
+ // TODO: Skipped because running creating multiple TorClient at the same time
+ // is not supported.
+ //
+ // Re-enable these when #1497 is closed.
+ t.skip("tests/testcases/hsc/*.toml");
+ t.skip("tests/testcases/hsc/*.md");
+ } else {
+ // This is not yet implemented, see #1487
+ t.skip("tests/testcases/hsc-feature-missing/*.toml");
+ t.skip("tests/testcases/hsc-feature-missing/*.md");
+ }
+ }
+
+ t.case("README.md");
+
+ // Run the tests.
+ //
+ // Note: the TestCases must be dropped *before* the tempdir
+ // (otherwise HOME will get cleaned up before the tests have had a chance to run!)
+ drop(t);
+}
diff --git a/crates/arti/tests/testcases/hsc-feature-missing/hsc.in/hsc.toml b/crates/arti/tests/testcases/hsc-feature-missing/hsc.in/hsc.toml
new file mode 100644
index 000000000..9f9c701f1
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc-feature-missing/hsc.in/hsc.toml
@@ -0,0 +1,11 @@
+[application]
+allow_running_as_root = true
+
+[storage]
+state_dir = "./local"
+
+[storage.permissions]
+dangerously_trust_everyone = true
+
+[logging]
+console = "warn"
diff --git a/crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/keystore/client/mnyizjj7m3hpcr7i5afph3zt7maa65johyu2ruis6z7cmnjmaj3h6tad/ks_hsc_desc_enc.x25519_private b/crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/keystore/client/mnyizjj7m3hpcr7i5afph3zt7maa65johyu2ruis6z7cmnjmaj3h6tad/ks_hsc_desc_enc.x25519_private
new file mode 100644
index 000000000..3089776c9
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/keystore/client/mnyizjj7m3hpcr7i5afph3zt7maa65johyu2ruis6z7cmnjmaj3h6tad/ks_hsc_desc_enc.x25519_private
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAQgAAABp4MjU1MT
+lAc3BlYy50b3Jwcm9qZWN0Lm9yZwAAACCNrKwy3SXHTOiSGMXywSI3ouBHfF3bKdyyx5LI
+Os0dWwAAAHj5tlsh+bZbIQAAABp4MjU1MTlAc3BlYy50b3Jwcm9qZWN0Lm9yZwAAACCNrK
+wy3SXHTOiSGMXywSI3ouBHfF3bKdyyx5LIOs0dWwAAACAO5qh4FRo41KE2Q7D5VACR8Rnu
+3zdBIVgjwDVRX7ByegAAAAABAgMEBQY=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/state/circuit_timeouts.json b/crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/state/circuit_timeouts.json
new file mode 100644
index 000000000..404293a15
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/state/circuit_timeouts.json
@@ -0,0 +1,5 @@
+{
+ "version": 1,
+ "histogram": [],
+ "current_timeout": 60000
+} \ No newline at end of file
diff --git a/crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/state/guards.json b/crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/state/guards.json
new file mode 100644
index 000000000..e3af2c5ef
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/state/guards.json
@@ -0,0 +1,14 @@
+{
+ "default": {
+ "guards": [],
+ "confirmed": []
+ },
+ "restricted": {
+ "guards": [],
+ "confirmed": []
+ },
+ "bridges": {
+ "guards": [],
+ "confirmed": []
+ }
+} \ No newline at end of file
diff --git a/crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/state/state.lock b/crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/state/state.lock
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc-feature-missing/hsc.in/local/state/state.lock
diff --git a/crates/arti/tests/testcases/hsc-feature-missing/hsc.md b/crates/arti/tests/testcases/hsc-feature-missing/hsc.md
new file mode 100644
index 000000000..c9651ab9c
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc-feature-missing/hsc.md
@@ -0,0 +1,9 @@
+# `arti hsc`
+
+`arti hsc` is only supported in builds that have the `onion-service-client`,
+`keymgr`, and `experimental-api` features enabled:
+
+```console
+$ arti hsc --help
+error: unrecognized subcommand 'hsc' (hint: recompile with the onion-service-client, keymgr, experimental-api features)
+```
diff --git a/crates/arti/tests/testcases/hsc/conf/hsc.toml b/crates/arti/tests/testcases/hsc/conf/hsc.toml
new file mode 100644
index 000000000..f9c2cf63d
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc/conf/hsc.toml
@@ -0,0 +1,11 @@
+[application]
+allow_running_as_root = true
+
+[storage]
+state_dir = "./tests/testcases/hsc/hsc.in/local"
+
+[storage.permissions]
+dangerously_trust_everyone = true
+
+[logging]
+console = "warn"
diff --git a/crates/arti/tests/testcases/hsc/get-key-error.stderr b/crates/arti/tests/testcases/hsc/get-key-error.stderr
new file mode 100644
index 000000000..f8a38cd46
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc/get-key-error.stderr
@@ -0,0 +1 @@
+[..]error: Service discovery key not found. Rerun with --generate=if-needed to generate a new service discovery keypair
diff --git a/crates/arti/tests/testcases/hsc/get-key-error.stdout b/crates/arti/tests/testcases/hsc/get-key-error.stdout
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc/get-key-error.stdout
diff --git a/crates/arti/tests/testcases/hsc/get-key-error.toml b/crates/arti/tests/testcases/hsc/get-key-error.toml
new file mode 100644
index 000000000..1be0f4f9e
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc/get-key-error.toml
@@ -0,0 +1,3 @@
+bin.name = "arti"
+args = "-c ./tests/testcases/hsc/conf/hsc.toml hsc get-key --key-type=service-discovery --onion-name fpqqmiwzqiv63jczrshh4qcmlxw6gujcai3arobq23wikt7hk7ojadid.onion --generate=no --output -"
+status.code = 127
diff --git a/crates/arti/tests/testcases/hsc/help.stderr b/crates/arti/tests/testcases/hsc/help.stderr
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc/help.stderr
diff --git a/crates/arti/tests/testcases/hsc/help.stdout b/crates/arti/tests/testcases/hsc/help.stdout
new file mode 100644
index 000000000..adab2965f
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc/help.stdout
@@ -0,0 +1,18 @@
+Run state management commands for an Arti hidden service client
+
+Usage: arti hsc [OPTIONS] <COMMAND>
+
+Commands:
+ get-key Prepare a service discovery key for connecting to a service running in restricted
+ discovery mode
+ help Print this message or the help of the given subcommand(s)
+
+Options:
+ -c, --config <FILE> Specify which config file(s) to read. Defaults to
+ [File("[..]"),
+ Dir("[..]")]
+ -o <KEY=VALUE> Override config file parameters, using TOML-like syntax.
+ -l, --log-level <LEVEL> Override the log level (usually one of 'trace', 'debug',
+ 'info', 'warn', 'error').
+ --disable-fs-permission-checks Don't check permissions on the files we use.
+ -h, --help Print help
diff --git a/crates/arti/tests/testcases/hsc/help.toml b/crates/arti/tests/testcases/hsc/help.toml
new file mode 100644
index 000000000..424f3cf1c
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc/help.toml
@@ -0,0 +1,3 @@
+bin.name = "arti"
+args = "hsc --help"
+status.code = 0
diff --git a/crates/arti/tests/testcases/hsc/hsc.in/hsc.toml b/crates/arti/tests/testcases/hsc/hsc.in/hsc.toml
new file mode 100644
index 000000000..9f9c701f1
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc/hsc.in/hsc.toml
@@ -0,0 +1,11 @@
+[application]
+allow_running_as_root = true
+
+[storage]
+state_dir = "./local"
+
+[storage.permissions]
+dangerously_trust_everyone = true
+
+[logging]
+console = "warn"
diff --git a/crates/arti/tests/testcases/hsc/hsc.in/local/keystore/client/mnyizjj7m3hpcr7i5afph3zt7maa65johyu2ruis6z7cmnjmaj3h6tad/ks_hsc_desc_enc.x25519_private b/crates/arti/tests/testcases/hsc/hsc.in/local/keystore/client/mnyizjj7m3hpcr7i5afph3zt7maa65johyu2ruis6z7cmnjmaj3h6tad/ks_hsc_desc_enc.x25519_private
new file mode 100644
index 000000000..3089776c9
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc/hsc.in/local/keystore/client/mnyizjj7m3hpcr7i5afph3zt7maa65johyu2ruis6z7cmnjmaj3h6tad/ks_hsc_desc_enc.x25519_private
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAQgAAABp4MjU1MT
+lAc3BlYy50b3Jwcm9qZWN0Lm9yZwAAACCNrKwy3SXHTOiSGMXywSI3ouBHfF3bKdyyx5LI
+Os0dWwAAAHj5tlsh+bZbIQAAABp4MjU1MTlAc3BlYy50b3Jwcm9qZWN0Lm9yZwAAACCNrK
+wy3SXHTOiSGMXywSI3ouBHfF3bKdyyx5LIOs0dWwAAACAO5qh4FRo41KE2Q7D5VACR8Rnu
+3zdBIVgjwDVRX7ByegAAAAABAgMEBQY=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/crates/arti/tests/testcases/hsc/hsc.in/local/state/circuit_timeouts.json b/crates/arti/tests/testcases/hsc/hsc.in/local/state/circuit_timeouts.json
new file mode 100644
index 000000000..404293a15
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc/hsc.in/local/state/circuit_timeouts.json
@@ -0,0 +1,5 @@
+{
+ "version": 1,
+ "histogram": [],
+ "current_timeout": 60000
+} \ No newline at end of file
diff --git a/crates/arti/tests/testcases/hsc/hsc.in/local/state/guards.json b/crates/arti/tests/testcases/hsc/hsc.in/local/state/guards.json
new file mode 100644
index 000000000..e3af2c5ef
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc/hsc.in/local/state/guards.json
@@ -0,0 +1,14 @@
+{
+ "default": {
+ "guards": [],
+ "confirmed": []
+ },
+ "restricted": {
+ "guards": [],
+ "confirmed": []
+ },
+ "bridges": {
+ "guards": [],
+ "confirmed": []
+ }
+} \ No newline at end of file
diff --git a/crates/arti/tests/testcases/hsc/hsc.in/local/state/state.lock b/crates/arti/tests/testcases/hsc/hsc.in/local/state/state.lock
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc/hsc.in/local/state/state.lock
diff --git a/crates/arti/tests/testcases/hsc/hsc.md b/crates/arti/tests/testcases/hsc/hsc.md
new file mode 100644
index 000000000..0e25a480d
--- /dev/null
+++ b/crates/arti/tests/testcases/hsc/hsc.md
@@ -0,0 +1,12 @@
+# `arti hsc`
+
+## The `get-key` subcommand
+
+Prepare a service discovery key:
+
+```console
+$ arti -c hsc.toml hsc get-key --key-type=service-discovery
+> --onion-name mnyizjj7m3hpcr7i5afph3zt7maa65johyu2ruis6z7cmnjmaj3h6tad.onion
+> --generate=no --output -
+descriptor:x25519:RWWKYMW5EXDUZ2ESDDC7FQJCG6ROAR34LXNSTXFSY6JMQOWNDVNQ
+```
diff --git a/crates/arti/tests/testcases/hss-feature-missing/hss.in/hss.toml b/crates/arti/tests/testcases/hss-feature-missing/hss.in/hss.toml
new file mode 100644
index 000000000..a6a0a482b
--- /dev/null
+++ b/crates/arti/tests/testcases/hss-feature-missing/hss.in/hss.toml
@@ -0,0 +1,13 @@
+[application]
+allow_running_as_root = true
+
+[storage]
+state_dir = "./local"
+
+[storage.permissions]
+dangerously_trust_everyone = true
+
+[logging]
+console = "warn"
+
+[onion_services."acutus-cepa"]
diff --git a/crates/arti/tests/testcases/hss-feature-missing/hss.in/local/keystore/hss/acutus-cepa/ks_hs_id.ed25519_expanded_private b/crates/arti/tests/testcases/hss-feature-missing/hss.in/local/keystore/hss/acutus-cepa/ks_hs_id.ed25519_expanded_private
new file mode 100644
index 000000000..e7ca44495
--- /dev/null
+++ b/crates/arti/tests/testcases/hss-feature-missing/hss.in/local/keystore/hss/acutus-cepa/ks_hs_id.ed25519_expanded_private
@@ -0,0 +1,8 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAATAAAACRlZDI1NT
+E5LWV4cGFuZGVkQHNwZWMudG9ycHJvamVjdC5vcmcAAAAgY3CMpT9mzvFH6OgK8+8z+wAP
+dS4+KajREvZ+JjUsAnYAAACgIP5WeyD+VnsAAAAkZWQyNTUxOS1leHBhbmRlZEBzcGVjLn
+RvcnByb2plY3Qub3JnAAAAIGNwjKU/Zs7xR+joCvPvM/sAD3UuPimo0RL2fiY1LAJ2AAAA
+QA/QV+74kAKl8QDDu8iB8hfbuDFuYDIQUE+tDVV7uYcH80JBy1/sjWq4bMwVe1ZyhjRs4h
+wJ3R9Q5vTT0dVwxV8AAAAAAQIDBA==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/crates/arti/tests/testcases/hss-feature-missing/hss.md b/crates/arti/tests/testcases/hss-feature-missing/hss.md
new file mode 100644
index 000000000..a2d8ce142
--- /dev/null
+++ b/crates/arti/tests/testcases/hss-feature-missing/hss.md
@@ -0,0 +1,9 @@
+# `arti hss`
+
+`arti hss` is only supported in builds that have the `onion-service-service`
+feature enabled:
+
+```console
+$ arti -c hss.toml hss --nickname acutus-cepa onion-name
+error: unrecognized subcommand 'hss' (hint: recompile with the onion-service-service feature)
+```
diff --git a/crates/arti/tests/testcases/hss/help.stderr b/crates/arti/tests/testcases/hss/help.stderr
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/crates/arti/tests/testcases/hss/help.stderr
diff --git a/crates/arti/tests/testcases/hss/help.stdout b/crates/arti/tests/testcases/hss/help.stdout
new file mode 100644
index 000000000..929a283b8
--- /dev/null
+++ b/crates/arti/tests/testcases/hss/help.stdout
@@ -0,0 +1,18 @@
+Run state management commands for an Arti hidden service
+
+Usage: arti hss [OPTIONS] --nickname <HS_NICKNAME> <COMMAND>
+
+Commands:
+ onion-name Print the .onion address of a hidden service
+ help Print this message or the help of the given subcommand(s)
+
+Options:
+ -c, --config <FILE> Specify which config file(s) to read. Defaults to
+ [File("[..]"),
+ Dir("[..]")]
+ -n, --nickname <HS_NICKNAME> The nickname of the service
+ -o <KEY=VALUE> Override config file parameters, using TOML-like syntax.
+ -l, --log-level <LEVEL> Override the log level (usually one of 'trace', 'debug',
+ 'info', 'warn', 'error').
+ --disable-fs-permission-checks Don't check permissions on the files we use.
+ -h, --help Print help
diff --git a/crates/arti/tests/testcases/hss/help.toml b/crates/arti/tests/testcases/hss/help.toml
new file mode 100644
index 000000000..8265de5cf
--- /dev/null
+++ b/crates/arti/tests/testcases/hss/help.toml
@@ -0,0 +1,3 @@
+bin.name = "arti"
+args = "hss --help"
+status.code = 0
diff --git a/crates/arti/tests/testcases/hss/hss.in/hss.toml b/crates/arti/tests/testcases/hss/hss.in/hss.toml
new file mode 100644
index 000000000..12f98bc80
--- /dev/null
+++ b/crates/arti/tests/testcases/hss/hss.in/hss.toml
@@ -0,0 +1,17 @@
+[application]
+allow_running_as_root = true
+
+[storage]
+state_dir = "./local"
+
+[storage.permissions]
+dangerously_trust_everyone = true
+
+[logging]
+console = "warn"
+
+[onion_services."acutus-cepa"]
+proxy_ports = [
+ # Forward port 80 on the service to localhost:10080.
+ ["80", "127.0.0.1:10080"],
+]
diff --git a/crates/arti/tests/testcases/hss/hss.in/local/keystore/hss/acutus-cepa/ks_hs_id.ed25519_expanded_private b/crates/arti/tests/testcases/hss/hss.in/local/keystore/hss/acutus-cepa/ks_hs_id.ed25519_expanded_private
new file mode 100644
index 000000000..e7ca44495
--- /dev/null
+++ b/crates/arti/tests/testcases/hss/hss.in/local/keystore/hss/acutus-cepa/ks_hs_id.ed25519_expanded_private
@@ -0,0 +1,8 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAATAAAACRlZDI1NT
+E5LWV4cGFuZGVkQHNwZWMudG9ycHJvamVjdC5vcmcAAAAgY3CMpT9mzvFH6OgK8+8z+wAP
+dS4+KajREvZ+JjUsAnYAAACgIP5WeyD+VnsAAAAkZWQyNTUxOS1leHBhbmRlZEBzcGVjLn
+RvcnByb2plY3Qub3JnAAAAIGNwjKU/Zs7xR+joCvPvM/sAD3UuPimo0RL2fiY1LAJ2AAAA
+QA/QV+74kAKl8QDDu8iB8hfbuDFuYDIQUE+tDVV7uYcH80JBy1/sjWq4bMwVe1ZyhjRs4h
+wJ3R9Q5vTT0dVwxV8AAAAAAQIDBA==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/crates/arti/tests/testcases/hss/hss.md b/crates/arti/tests/testcases/hss/hss.md
new file mode 100644
index 000000000..da4977896
--- /dev/null
+++ b/crates/arti/tests/testcases/hss/hss.md
@@ -0,0 +1,14 @@
+# `arti hss`
+
+## The `onion-name` subcommand
+
+Print the `.onion` address of a hidden service:
+
+```console
+$ arti -c hss.toml hss --nickname acutus-cepa onion-name
+mnyizjj7m3hpcr7i5afph3zt7maa65johyu2ruis6z7cmnjmaj3h6tad.onion
+
+$ arti -c hss.toml hss --nickname flamingo onion-name
+Service flamingo is not configured
+
+```