""" Tests for SSH Keys API routes. Tests the following endpoints: - POST /api/ssh-keys - GET /api/ssh-keys - GET /api/ssh-keys/{id} - DELETE /api/ssh-keys/{id} """ import pytest from fastapi.testclient import TestClient # Valid SSH private key for testing VALID_SSH_KEY = """-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW QyNTUxOQAAACB5WfkA8wgP/KvdGFNC1ZCbBmjZnKpM/LOXRDJS7NfRAQAAAJC9AVH1vQFR AAAAAtzc2gtZWQyNTUxOQAAACB5WfkA8wgP/KvdGFNC1ZCbBmjZnKpM/LOXRDJS7NfRAQA AAECB5WfkA8wgP/KvdGFNC1ZCbBmjZnKpM/LOXRDJS7NfRAQAAAHHZpXRvaXRvQVJNVjJH AAAAFGZpbGVzeXN0ZW0uY2ZnAAAAAQAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAA/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAEAAAAEWNvbW1lbnQ6IHRlc3Qga2V5AQIDBAUHBg==""" # Invalid SSH key for testing INVALID_SSH_KEY = "not-a-valid-ssh-key" class TestCreateSshKey: """Tests for POST /api/ssh-keys endpoint.""" def test_create_ssh_key_success(self, client: TestClient): """Test creating a new SSH key successfully.""" response = client.post( "/api/ssh-keys", json={ "name": "test-key", "private_key": VALID_SSH_KEY }, headers={"Authorization": "Bearer test-token"} ) assert response.status_code == 201 data = response.json() assert data["code"] == 0 assert data["message"] == "SSH key created successfully" assert data["data"]["name"] == "test-key" assert data["data"]["id"] > 0 assert data["data"]["fingerprint"] is not None assert data["data"]["created_at"] > 0 def test_create_ssh_key_duplicate_name(self, client: TestClient): """Test creating a SSH key with duplicate name fails.""" # Create first key client.post( "/api/ssh-keys", json={ "name": "duplicate-key", "private_key": VALID_SSH_KEY }, headers={"Authorization": "Bearer test-token"} ) # Try to create duplicate response = client.post( "/api/ssh-keys", json={ "name": "duplicate-key", "private_key": VALID_SSH_KEY }, headers={"Authorization": "Bearer test-token"} ) assert response.status_code == 400 data = response.json() assert "already exists" in data["detail"] def test_create_ssh_key_invalid_key_format(self, client: TestClient): """Test creating a SSH key with invalid format fails.""" response = client.post( "/api/ssh-keys", json={ "name": "invalid-key", "private_key": INVALID_SSH_KEY }, headers={"Authorization": "Bearer test-token"} ) assert response.status_code == 400 data = response.json() assert "Invalid SSH private key format" in data["detail"] def test_create_ssh_key_empty_name(self, client: TestClient): """Test creating a SSH key with empty name fails.""" response = client.post( "/api/ssh-keys", json={ "name": "", "private_key": VALID_SSH_KEY }, headers={"Authorization": "Bearer test-token"} ) assert response.status_code == 422 # Validation error def test_create_ssh_key_no_auth(self, client: TestClient): """Test creating a SSH key without authentication fails.""" response = client.post( "/api/ssh-keys", json={ "name": "test-key", "private_key": VALID_SSH_KEY } ) assert response.status_code == 401 def test_create_ssh_key_invalid_token(self, client: TestClient): """Test creating a SSH key with invalid token fails.""" response = client.post( "/api/ssh-keys", json={ "name": "test-key", "private_key": VALID_SSH_KEY }, headers={"Authorization": "Bearer invalid-token"} ) assert response.status_code == 401 class TestListSshKeys: """Tests for GET /api/ssh-keys endpoint.""" def test_list_ssh_keys_empty(self, client: TestClient): """Test listing SSH keys when none exist.""" response = client.get( "/api/ssh-keys", headers={"Authorization": "Bearer test-token"} ) assert response.status_code == 200 data = response.json() assert data["code"] == 0 assert data["data"] == [] assert "0 SSH key" in data["message"] def test_list_ssh_keys_with_items(self, client: TestClient): """Test listing SSH keys when some exist.""" # Create some keys client.post( "/api/ssh-keys", json={"name": "key-1", "private_key": VALID_SSH_KEY}, headers={"Authorization": "Bearer test-token"} ) client.post( "/api/ssh-keys", json={"name": "key-2", "private_key": VALID_SSH_KEY}, headers={"Authorization": "Bearer test-token"} ) response = client.get( "/api/ssh-keys", headers={"Authorization": "Bearer test-token"} ) assert response.status_code == 200 data = response.json() assert data["code"] == 0 assert len(data["data"]) == 2 assert data["data"][0]["name"] in ["key-1", "key-2"] assert "private_key" not in data["data"][0] # Should not expose private key def test_list_ssh_keys_no_auth(self, client: TestClient): """Test listing SSH keys without authentication fails.""" response = client.get("/api/ssh-keys") assert response.status_code == 401 class TestGetSshKey: """Tests for GET /api/ssh-keys/{id} endpoint.""" def test_get_ssh_key_success(self, client: TestClient): """Test getting a specific SSH key successfully.""" # Create a key first create_response = client.post( "/api/ssh-keys", json={"name": "get-test-key", "private_key": VALID_SSH_KEY}, headers={"Authorization": "Bearer test-token"} ) key_id = create_response.json()["data"]["id"] # Get the key response = client.get( f"/api/ssh-keys/{key_id}", headers={"Authorization": "Bearer test-token"} ) assert response.status_code == 200 data = response.json() assert data["code"] == 0 assert data["data"]["id"] == key_id assert data["data"]["name"] == "get-test-key" assert "private_key" not in data["data"] def test_get_ssh_key_not_found(self, client: TestClient): """Test getting a non-existent SSH key fails.""" response = client.get( "/api/ssh-keys/99999", headers={"Authorization": "Bearer test-token"} ) assert response.status_code == 404 assert "not found" in response.json()["detail"] def test_get_ssh_key_no_auth(self, client: TestClient): """Test getting an SSH key without authentication fails.""" response = client.get("/api/ssh-keys/1") assert response.status_code == 401 class TestDeleteSshKey: """Tests for DELETE /api/ssh-keys/{id} endpoint.""" def test_delete_ssh_key_success(self, client: TestClient): """Test deleting an SSH key successfully.""" # Create a key first create_response = client.post( "/api/ssh-keys", json={"name": "delete-test-key", "private_key": VALID_SSH_KEY}, headers={"Authorization": "Bearer test-token"} ) key_id = create_response.json()["data"]["id"] # Delete the key response = client.delete( f"/api/ssh-keys/{key_id}", headers={"Authorization": "Bearer test-token"} ) assert response.status_code == 200 data = response.json() assert data["code"] == 0 assert data["message"] == "SSH key deleted successfully" # Verify it's deleted get_response = client.get( f"/api/ssh-keys/{key_id}", headers={"Authorization": "Bearer test-token"} ) assert get_response.status_code == 404 def test_delete_ssh_key_not_found(self, client: TestClient): """Test deleting a non-existent SSH key fails.""" response = client.delete( "/api/ssh-keys/99999", headers={"Authorization": "Bearer test-token"} ) assert response.status_code == 404 def test_delete_ssh_key_in_use(self, client: TestClient): """Test deleting an SSH key that is in use by a server fails.""" # Create an SSH key ssh_response = client.post( "/api/ssh-keys", json={"name": "in-use-key", "private_key": VALID_SSH_KEY}, headers={"Authorization": "Bearer test-token"} ) ssh_key_id = ssh_response.json()["data"]["id"] # Create a server using this key client.post( "/api/servers", json={ "name": "test-server", "url": "https://gitea.example.com", "api_token": "test-api-token", "ssh_key_id": ssh_key_id }, headers={"Authorization": "Bearer test-token"} ) # Try to delete the SSH key response = client.delete( f"/api/ssh-keys/{ssh_key_id}", headers={"Authorization": "Bearer test-token"} ) assert response.status_code == 400 assert "in use" in response.json()["detail"].lower() def test_delete_ssh_key_no_auth(self, client: TestClient): """Test deleting an SSH key without authentication fails.""" response = client.delete("/api/ssh-keys/1") assert response.status_code == 401