Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/check-examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ jobs:
python-version: '3.13'
- name: Install local keyring and pinned Sotto release
env:
SOTTO_VERSION: v0.6.0
SOTTO_VERSION: v0.9.0
run: |
sudo apt-get update -qq
sudo apt-get install -y gnome-keyring dbus-x11
curl -fsSL https://raw.githubusercontent.com/getsotto/sotto/be30886644d321929b371aa56cf0e528c6a8edb9/install.sh | sh
curl -fsSL https://raw.githubusercontent.com/getsotto/sotto/fbd4f2542daf5580da361aabe93e8804758df6b5/install.sh | sh
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- name: Run the documented flow in a disposable keyring
run: |
Expand Down
70 changes: 65 additions & 5 deletions scripts/check_sotto.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Exercise the real local Sotto flow on a disposable Linux CI runner only."""

import json
import os
from pathlib import Path
import subprocess
Expand All @@ -10,7 +11,7 @@


def main():
# SOTTO_DATA_DIR does not isolate OS-keychain entries. Never initialise a
# SOTTO_DATA_DIR does not isolate OS keychain entries. Never initialise a
# throwaway identity in a developer's real keychain.
if sys.platform != "linux" or os.environ.get("GITHUB_ACTIONS") != "true":
raise SystemExit("Run this check only on the disposable Linux GitHub Actions runner.")
Expand All @@ -22,20 +23,79 @@ def main():
env["SOTTO_PASSWORD"] = "disposable-ci-demo-password"

def run(command, expected, stdin=None):
result = subprocess.run(command, cwd=folder, env=env, input=stdin, text=True, capture_output=True, timeout=120)
result = subprocess.run(
command,
cwd=folder,
env=env,
input=stdin,
text=True,
capture_output=True,
timeout=120,
)
if result.returncode != expected:
raise SystemExit(f"Unexpected exit status from {command[0]}; output withheld to keep the Emergency Kit private.")
raise SystemExit(
f"Unexpected exit status from {command[:2]}; output withheld to keep the Emergency Kit private."
)
return result

def status():
return json.loads(run(["sotto", "status", "--json"], 0).stdout)

python = [sys.executable, str(ROOT / "python/main.py")]
run(python, 1)

if status() != {"initialized": False, "unlocked": False, "project": None}:
raise SystemExit("Unexpected initial status before init.")

run(["sotto", "init", "--name", "sotto-example"], 0)

if status() != {
"initialized": True,
"unlocked": True,
"project": {"name": "sotto-example", "environment": "dev"},
}:
raise SystemExit("Unexpected status after init.")

envs_out = run(["sotto", "env", "ls"], 0).stdout
envs = {line.lstrip("* ").strip() for line in envs_out.splitlines() if line.strip()}
if envs != {"dev", "staging", "prod"}:
raise SystemExit("Unexpected environment list after init.")

run(["sotto", "set", "DEMO_SECRET", "--stdin"], 0, "hello-from-sotto")

if json.loads(run(["sotto", "ls", "--json"], 0).stdout) != ["DEMO_SECRET"]:
raise SystemExit("Unexpected secret list in dev.")

result = run(["sotto", "run", "--", *python], 0)
if result.stdout != "Sotto demo: secret loaded successfully.\n":
raise SystemExit("Unexpected demo output (withheld).")
raise SystemExit("Unexpected demo output in dev (withheld).")

run(["sotto", "env", "copy", "dev", "staging", "--confirm"], 0)
staging_result = run(["sotto", "run", "--env", "staging", "--", *python], 0)
if staging_result.stdout != "Sotto demo: secret loaded successfully.\n":
raise SystemExit("Unexpected demo output in staging (withheld).")

dotenv_path = Path(folder) / ".env.staging"
dotenv_path.write_text("IMPORTED_KEY=synthetic-dotenv-value\n", encoding="utf-8")
run(["sotto", "import", "--env", "staging", str(dotenv_path)], 0)
if json.loads(run(["sotto", "ls", "--env", "staging", "--json"], 0).stdout) != [
"DEMO_SECRET",
"IMPORTED_KEY",
]:
raise SystemExit("Unexpected secret list in staging after dotenv import.")

run(["sotto", "lock"], 0)
if status()["unlocked"] is not False:
raise SystemExit("Expected session to be locked after sotto lock.")

run(["sotto", "unlock"], 0)
if status()["unlocked"] is not True:
raise SystemExit("Expected session to be unlocked after sotto unlock.")

run(python, 1)
print("PASS real Sotto: missing -> init -> set -> injected success -> direct run still missing")
print(
"PASS real Sotto: status -> init -> env ls -> set -> ls -> run -> env copy -> import -> lock/unlock -> direct run still missing"
)


if __name__ == "__main__":
Expand Down
Loading