fix: allow vault info under path scope and clarify API errors
Build and Push Docker Container / build-and-push (push) Successful in 4m29s
Build and Push Docker Container / build-and-push (push) Successful in 4m29s
- Allow vault and vaults commands when a token has path restrictions - Treat vault/vaults as pathless metadata commands in policy checks - Add allowed commands, vaults and paths to 403 permission errors - Surface real JWT failure reason in 401 instead of generic Unauthorized - Report missing, malformed and empty Bearer tokens distinctly - Catch httpRequest failures in the n8n node to avoid circular JSON - Map API errors to clean NodeApiError with status code and detail - Support continueOnFail with per-item error output in the n8n node - Push a versioned image tag from pyproject in the CI workflow - Bump server to 1.0.2 and n8n node package to 0.2.1 - Add tests for vault info access and richer auth error messages
This commit is contained in:
+37
-3
@@ -50,6 +50,19 @@ def test_command_requires_auth():
|
||||
response = client.post("/commands", json={"args": ["--version"]})
|
||||
|
||||
assert response.status_code == 401
|
||||
assert response.json()["detail"] == "missing Authorization header; expected 'Bearer <jwt>'"
|
||||
|
||||
def test_invalid_token_reports_reason(monkeypatch):
|
||||
monkeypatch.setattr("app.auth.JWT_SECRET", "secret")
|
||||
|
||||
response = client.post(
|
||||
"/commands",
|
||||
headers={"Authorization": "Bearer not-a-jwt"},
|
||||
json={"args": ["--version"]},
|
||||
)
|
||||
|
||||
assert response.status_code == 401
|
||||
assert response.json()["detail"].startswith("invalid token:")
|
||||
|
||||
def test_command_runs_configured_cli_only():
|
||||
response = client.post(
|
||||
@@ -118,7 +131,7 @@ def test_token_policy_restricts_command(monkeypatch):
|
||||
)
|
||||
|
||||
assert response.status_code == 403
|
||||
assert response.json()["detail"] == "token is not allowed to run command: create"
|
||||
assert response.json()["detail"].startswith("token is not allowed to run command: create")
|
||||
|
||||
def test_token_policy_restricts_vault(monkeypatch):
|
||||
token = use_jwt_auth(monkeypatch, {"sub": "work", "commands": ["*"], "vaults": ["work"], "paths": ["*"]})
|
||||
@@ -130,7 +143,7 @@ def test_token_policy_restricts_vault(monkeypatch):
|
||||
)
|
||||
|
||||
assert response.status_code == 403
|
||||
assert response.json()["detail"] == "token is not allowed to access vault: personal"
|
||||
assert response.json()["detail"].startswith("token is not allowed to access vault: personal")
|
||||
|
||||
def test_token_policy_restricts_path(monkeypatch):
|
||||
token = use_jwt_auth(monkeypatch, {"sub": "inbox", "commands": ["read"], "vaults": ["*"], "paths": ["Inbox/"]})
|
||||
@@ -142,7 +155,7 @@ def test_token_policy_restricts_path(monkeypatch):
|
||||
)
|
||||
|
||||
assert response.status_code == 403
|
||||
assert response.json()["detail"] == "token is not allowed to access path: Private/Secret.md"
|
||||
assert response.json()["detail"].startswith("token is not allowed to access path: Private/Secret.md")
|
||||
|
||||
def test_token_policy_allows_allowed_path(monkeypatch):
|
||||
token = use_jwt_auth(monkeypatch, {"sub": "inbox", "commands": ["read"], "vaults": ["*"], "paths": ["Inbox/"]})
|
||||
@@ -185,6 +198,27 @@ def test_path_restricted_token_allows_daily_command_from_obsidian_config(monkeyp
|
||||
assert response.status_code == 200
|
||||
assert response.json()["command"] == ["python", "vault=work", "daily:append", "content=ok"]
|
||||
|
||||
def test_path_restricted_token_allows_vault_info_command(monkeypatch):
|
||||
token = use_jwt_auth(monkeypatch, {"sub": "daily", "commands": ["daily:append", "vault", "vaults"], "vaults": ["*"], "paths": ["00. Journal/"]})
|
||||
|
||||
response = client.post(
|
||||
"/commands",
|
||||
headers={"Authorization": f"Bearer {token}"},
|
||||
json={"args": ["vault"]},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["command"] == ["python", "vault"]
|
||||
|
||||
response = client.post(
|
||||
"/commands",
|
||||
headers={"Authorization": f"Bearer {token}"},
|
||||
json={"args": ["vaults"]},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["command"] == ["python", "vaults"]
|
||||
|
||||
def test_path_restricted_token_denies_daily_command_outside_obsidian_config(monkeypatch, tmp_path):
|
||||
vault = tmp_path / "vault"
|
||||
config = vault / ".obsidian"
|
||||
|
||||
Reference in New Issue
Block a user