borescope 1.0.0__tar.gz → 1.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {borescope-1.0.0 → borescope-1.0.2}/PKG-INFO +19 -3
- {borescope-1.0.0 → borescope-1.0.2}/README.md +18 -2
- {borescope-1.0.0 → borescope-1.0.2}/pyproject.toml +1 -1
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/cli.py +8 -0
- borescope-1.0.2/src/borescope/snap.py +62 -0
- borescope-1.0.2/tests/test_snap.py +90 -0
- {borescope-1.0.0 → borescope-1.0.2}/.gitignore +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/LICENSE +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/__init__.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/__main__.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/discovery.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/errors.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/juju.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/__init__.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/commands/__init__.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/commands/_args.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/commands/base.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/commands/basic.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/commands/execcmd.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/commands/filesystem.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/commands/pebble.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/completion.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/context.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/history.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/output.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/parser.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/pathutils.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/repl.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/sanitise.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/shell/theme.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/snapshot.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/transport/__init__.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/transport/cli_transport.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/transport/relay.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/transport/runner.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/src/borescope/transport/socket_transport.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/charms/bareshell-test/.gitignore +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/charms/bareshell-test/Makefile +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/charms/bareshell-test/README.md +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/charms/bareshell-test/charmcraft.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/charms/bareshell-test/requirements.txt +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/charms/bareshell-test/src/charm.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/charms/bareshell-test/workload-src/go.mod +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/charms/bareshell-test/workload-src/main.go +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/cloud-config.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/conftest.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/fuzz/README.md +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/fuzz/corpus/mixed_quoting +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/fuzz/corpus/pipe_command +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/fuzz/corpus/pipe_with_flags +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/fuzz/corpus/simple_command +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/fuzz/corpus/single_quoted_arg +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/fuzz/corpus/tilde_expansion +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/fuzz/corpus/variable_expansion +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/fuzz/corpus/whitespace_only +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/fuzz/fuzz_parser.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/integration/__init__.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/integration/conftest.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/integration/test_socket.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/cat-missing-file-errors/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/cat-multiple-files-concatenated/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/cat-no-args-reads-stdin/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/cat-single-file/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/cd-absolute-path/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/cd-into-file-errors/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/cd-no-args-goes-home/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/cd-relative-path/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/cp-file-to-existing-dir/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/cp-file-to-file/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/cp-missing-source-errors/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/double-quoted-tilde-is-literal/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/double-quotes-expand-var/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/echo-empty-string-arg-divergence/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/echo-multiple-args/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/echo-no-args-divergence/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/env-lists-tracked-variables/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/exit-default-zero/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/exit-non-numeric-arg-divergence/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/exit-with-code/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/expand-no-expansion-in-single-quotes/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/expand-tilde-alone/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/expand-tilde-not-at-word-start/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/expand-tilde-prefix/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/expand-unknown-var-empty/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/expand-var-braces/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/expand-var-dollar/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/find-by-name-pattern/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/find-by-type-directory/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/find-by-type-file/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/grep-basic-match-exit-0/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/grep-case-insensitive-i/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/grep-count-c/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/grep-invalid-pattern-divergence/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/grep-invert-v/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/grep-line-numbers-n/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/grep-multiple-files-prefixed/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/grep-no-match-exit-1/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/head-default-10-lines/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/head-missing-file-errors/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/head-n-flag/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/lib.sh +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/ls-a-shows-hidden/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/ls-default-no-hidden/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/ls-multiple-operands-headered/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/mixed-quoting-within-word/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/mkdir-create/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/mkdir-existing-errors/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/mkdir-p-creates-parents/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/mkdir-p-existing-ok/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/mv-into-existing-dir/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/mv-rename/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/pipe-empty-stage-rejected/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/pipe-quoted-bar-is-literal/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/pipe-two-stage/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/pwd-default-root/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/quoted-operator-literal-arg/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/rm-existing-file/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/rm-missing-with-f-ok/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/rm-missing-without-f-errors/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/rm-non-empty-dir-without-r-errors/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/rm-recursive/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/sequencing-semicolon-divergence/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/tail-default-10-lines/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/tail-n-flag/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/tokenize-double-quotes/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/touch-creates-new-file/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/touch-existing-updates-mtime-divergence/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/unbalanced-quote-is-error/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/unsupported-and-divergence/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/unsupported-multi-pipe-divergence/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/unsupported-or-divergence/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/unsupported-redirect-append-divergence/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/unsupported-redirect-in-divergence/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/spread/unsupported-redirect-out-divergence/task.yaml +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/test_args.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/test_cli.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/test_commands.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/test_completion.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/test_discovery.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/test_juju.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/test_parser.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/test_pathutils.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/test_pebble_commands.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/test_registry.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/test_relay.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/test_repl.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/test_runner.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/test_sanitise.py +0 -0
- {borescope-1.0.0 → borescope-1.0.2}/tests/test_snapshot.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: borescope
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: A natural shell for debugging Juju Kubernetes workload containers via Pebble
|
|
5
5
|
Project-URL: Homepage, https://github.com/tonyandrewmeyer/borescope
|
|
6
6
|
Project-URL: Repository, https://github.com/tonyandrewmeyer/borescope
|
|
@@ -54,10 +54,26 @@ can't, it fails the same way.
|
|
|
54
54
|
|
|
55
55
|
## Install
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
From the [snap store](https://snapcraft.io/borescope):
|
|
58
58
|
|
|
59
59
|
```console
|
|
60
|
-
|
|
60
|
+
sudo snap install borescope
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
A few things to know about the snap:
|
|
64
|
+
|
|
65
|
+
- It bundles its own juju (currently `juju/4/stable`), so it works
|
|
66
|
+
even without juju installed on the host.
|
|
67
|
+
- It reads your `~/.local/share/juju` (JUJU_DATA) read-only via the
|
|
68
|
+
auto-connecting `juju-client-observe` interface, then copies it into
|
|
69
|
+
a writable per-snap directory at startup. **Run `juju login` /
|
|
70
|
+
`juju switch` outside borescope** — changes made inside a borescope
|
|
71
|
+
session don't propagate back to the host JUJU_DATA.
|
|
72
|
+
|
|
73
|
+
Or from [PyPI](https://pypi.org/project/borescope/):
|
|
74
|
+
|
|
75
|
+
```console
|
|
76
|
+
uv tool install borescope # or: uvx borescope, pipx install borescope
|
|
61
77
|
```
|
|
62
78
|
|
|
63
79
|
## Usage
|
|
@@ -23,10 +23,26 @@ can't, it fails the same way.
|
|
|
23
23
|
|
|
24
24
|
## Install
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
From the [snap store](https://snapcraft.io/borescope):
|
|
27
27
|
|
|
28
28
|
```console
|
|
29
|
-
|
|
29
|
+
sudo snap install borescope
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
A few things to know about the snap:
|
|
33
|
+
|
|
34
|
+
- It bundles its own juju (currently `juju/4/stable`), so it works
|
|
35
|
+
even without juju installed on the host.
|
|
36
|
+
- It reads your `~/.local/share/juju` (JUJU_DATA) read-only via the
|
|
37
|
+
auto-connecting `juju-client-observe` interface, then copies it into
|
|
38
|
+
a writable per-snap directory at startup. **Run `juju login` /
|
|
39
|
+
`juju switch` outside borescope** — changes made inside a borescope
|
|
40
|
+
session don't propagate back to the host JUJU_DATA.
|
|
41
|
+
|
|
42
|
+
Or from [PyPI](https://pypi.org/project/borescope/):
|
|
43
|
+
|
|
44
|
+
```console
|
|
45
|
+
uv tool install borescope # or: uvx borescope, pipx install borescope
|
|
30
46
|
```
|
|
31
47
|
|
|
32
48
|
## Usage
|
|
@@ -107,6 +107,14 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
107
107
|
return 0
|
|
108
108
|
|
|
109
109
|
args = build_parser().parse_args(argv)
|
|
110
|
+
|
|
111
|
+
# When running as a snap, stage the host's JUJU_DATA into the snap's
|
|
112
|
+
# writable home so the bundled juju can refresh macaroons/cookies. No-op
|
|
113
|
+
# outside the snap. See borescope.snap for the trade-offs.
|
|
114
|
+
from .snap import stage_juju_data
|
|
115
|
+
|
|
116
|
+
stage_juju_data()
|
|
117
|
+
|
|
110
118
|
if not args.unit and not args.socket and not args.here:
|
|
111
119
|
print(
|
|
112
120
|
"borescope: A unit reference is required (for example 'borescope myapp/0'), "
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Copyright 2026 Tony Meyer
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
"""Snap-environment helpers.
|
|
5
|
+
|
|
6
|
+
Under strict confinement, the snap can only *read* the host's Juju
|
|
7
|
+
configuration directory via the ``juju-client-observe`` interface — it
|
|
8
|
+
cannot write to it. Borescope's bundled juju, however, refreshes
|
|
9
|
+
macaroons and cookies on the fly and will fail the moment it tries to
|
|
10
|
+
update ``cookies.yaml`` or ``accounts.yaml``.
|
|
11
|
+
|
|
12
|
+
Personal-files would grant write access but pushes the snap into manual
|
|
13
|
+
store review on every revision until an auto-connect declaration is
|
|
14
|
+
granted. To stay on auto-connecting interfaces, we instead stage a copy
|
|
15
|
+
of the host's ``~/.local/share/juju`` into the snap's writable
|
|
16
|
+
``$SNAP_USER_COMMON/juju`` on every invocation, point ``JUJU_DATA`` at
|
|
17
|
+
the copy, and let the bundled juju write freely to it.
|
|
18
|
+
|
|
19
|
+
Trade-offs of staging:
|
|
20
|
+
|
|
21
|
+
* The copy is one-way (host → snap). Logins/model-switches you do
|
|
22
|
+
*inside* a borescope session never write back to the host, so they
|
|
23
|
+
vanish at the end of the session. Do ``juju login`` / ``juju
|
|
24
|
+
switch`` *outside* borescope.
|
|
25
|
+
* The copy happens at every borescope invocation, so host-side changes
|
|
26
|
+
are picked up on the next run. For typical use (debug a workload,
|
|
27
|
+
exit, move on) this is invisible.
|
|
28
|
+
|
|
29
|
+
This module is a no-op outside the snap, so unit tests and PyPI
|
|
30
|
+
installs are unaffected.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
import os
|
|
36
|
+
import pwd
|
|
37
|
+
import shutil
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def stage_juju_data() -> None:
|
|
41
|
+
"""If running inside the borescope snap, copy host JUJU_DATA into writable storage.
|
|
42
|
+
|
|
43
|
+
The snap's ``apps.borescope.environment`` block sets
|
|
44
|
+
``JUJU_DATA=$SNAP_USER_COMMON/juju``; this function populates that
|
|
45
|
+
directory by copying ``~/.local/share/juju`` (read-only via
|
|
46
|
+
``juju-client-observe``) into it on every invocation. The bundled
|
|
47
|
+
juju then reads and writes the copy freely.
|
|
48
|
+
|
|
49
|
+
No-op outside the snap, and no-op if the host has no JUJU_DATA
|
|
50
|
+
(the bundled juju will surface "no controllers registered" itself).
|
|
51
|
+
"""
|
|
52
|
+
if os.environ.get('SNAP_NAME') != 'borescope':
|
|
53
|
+
return
|
|
54
|
+
snap_user_common = os.environ.get('SNAP_USER_COMMON')
|
|
55
|
+
if not snap_user_common:
|
|
56
|
+
return
|
|
57
|
+
real_home = pwd.getpwuid(os.getuid()).pw_dir
|
|
58
|
+
source = os.path.join(real_home, '.local', 'share', 'juju')
|
|
59
|
+
if not os.path.isdir(source):
|
|
60
|
+
return
|
|
61
|
+
target = os.path.join(snap_user_common, 'juju')
|
|
62
|
+
shutil.copytree(source, target, dirs_exist_ok=True, symlinks=True)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Copyright 2026 Tony Meyer
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
"""Tests for the snap startup hook that stages JUJU_DATA."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import pwd
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
12
|
+
from borescope.snap import stage_juju_data
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.fixture
|
|
16
|
+
def in_snap(monkeypatch, tmp_path):
|
|
17
|
+
"""Pretend we're running inside the borescope snap."""
|
|
18
|
+
real_home = tmp_path / 'home'
|
|
19
|
+
snap_common = tmp_path / 'snap-common'
|
|
20
|
+
source = real_home / '.local' / 'share' / 'juju'
|
|
21
|
+
target = snap_common / 'juju'
|
|
22
|
+
|
|
23
|
+
source.mkdir(parents=True)
|
|
24
|
+
snap_common.mkdir()
|
|
25
|
+
(source / 'controllers.yaml').write_text('controllers:\n k8s: {}\n')
|
|
26
|
+
(source / 'cookies.yaml').write_text('cookies: []\n')
|
|
27
|
+
|
|
28
|
+
monkeypatch.setenv('SNAP_NAME', 'borescope')
|
|
29
|
+
monkeypatch.setenv('SNAP_USER_COMMON', str(snap_common))
|
|
30
|
+
monkeypatch.setattr(
|
|
31
|
+
pwd,
|
|
32
|
+
'getpwuid',
|
|
33
|
+
lambda _uid: pwd.struct_passwd(('u', 'x', 0, 0, '', str(real_home), '/bin/sh')),
|
|
34
|
+
)
|
|
35
|
+
return source, target
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_noop_outside_snap(monkeypatch, tmp_path):
|
|
39
|
+
monkeypatch.delenv('SNAP_NAME', raising=False)
|
|
40
|
+
target = tmp_path / 'juju'
|
|
41
|
+
stage_juju_data()
|
|
42
|
+
assert not target.exists()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_noop_when_snap_name_is_something_else(monkeypatch):
|
|
46
|
+
monkeypatch.setenv('SNAP_NAME', 'jhack')
|
|
47
|
+
stage_juju_data() # must not raise
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_stages_when_host_juju_data_exists(in_snap):
|
|
51
|
+
source, target = in_snap
|
|
52
|
+
stage_juju_data()
|
|
53
|
+
assert (target / 'controllers.yaml').read_text() == (source / 'controllers.yaml').read_text()
|
|
54
|
+
assert (target / 'cookies.yaml').read_text() == (source / 'cookies.yaml').read_text()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_noop_when_host_juju_data_missing(monkeypatch, tmp_path):
|
|
58
|
+
real_home = tmp_path / 'home'
|
|
59
|
+
snap_common = tmp_path / 'snap-common'
|
|
60
|
+
real_home.mkdir()
|
|
61
|
+
snap_common.mkdir()
|
|
62
|
+
monkeypatch.setenv('SNAP_NAME', 'borescope')
|
|
63
|
+
monkeypatch.setenv('SNAP_USER_COMMON', str(snap_common))
|
|
64
|
+
monkeypatch.setattr(
|
|
65
|
+
pwd,
|
|
66
|
+
'getpwuid',
|
|
67
|
+
lambda _uid: pwd.struct_passwd(('u', 'x', 0, 0, '', str(real_home), '/bin/sh')),
|
|
68
|
+
)
|
|
69
|
+
stage_juju_data()
|
|
70
|
+
assert not (snap_common / 'juju').exists()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_subsequent_runs_pick_up_host_changes(in_snap):
|
|
74
|
+
source, target = in_snap
|
|
75
|
+
stage_juju_data()
|
|
76
|
+
assert (target / 'controllers.yaml').read_text().startswith('controllers:\n k8s')
|
|
77
|
+
(source / 'controllers.yaml').write_text('controllers:\n prod: {}\n')
|
|
78
|
+
stage_juju_data()
|
|
79
|
+
assert 'prod' in (target / 'controllers.yaml').read_text()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_inside_snap_writes_bundled_juju_cookies_to_copy(in_snap):
|
|
83
|
+
"""Writes by the bundled juju into the snap copy must not leak back to host."""
|
|
84
|
+
source, target = in_snap
|
|
85
|
+
stage_juju_data()
|
|
86
|
+
(target / 'cookies.yaml').write_text('cookies:\n - inside-snap\n')
|
|
87
|
+
# Re-run: host source is unchanged, target gets overwritten with host data.
|
|
88
|
+
stage_juju_data()
|
|
89
|
+
assert (source / 'cookies.yaml').read_text() == 'cookies: []\n'
|
|
90
|
+
assert (target / 'cookies.yaml').read_text() == 'cookies: []\n'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{borescope-1.0.0 → borescope-1.0.2}/tests/spread/expand-no-expansion-in-single-quotes/task.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{borescope-1.0.0 → borescope-1.0.2}/tests/spread/rm-non-empty-dir-without-r-errors/task.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{borescope-1.0.0 → borescope-1.0.2}/tests/spread/touch-existing-updates-mtime-divergence/task.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{borescope-1.0.0 → borescope-1.0.2}/tests/spread/unsupported-multi-pipe-divergence/task.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{borescope-1.0.0 → borescope-1.0.2}/tests/spread/unsupported-redirect-append-divergence/task.yaml
RENAMED
|
File without changes
|
{borescope-1.0.0 → borescope-1.0.2}/tests/spread/unsupported-redirect-in-divergence/task.yaml
RENAMED
|
File without changes
|
{borescope-1.0.0 → borescope-1.0.2}/tests/spread/unsupported-redirect-out-divergence/task.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|