cnos-firebase 1.12.0__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.
@@ -0,0 +1,33 @@
1
+ .coop/logs/
2
+ .coop/tmp/
3
+ node_modules/
4
+ dist/
5
+ coverage/
6
+ .artifacts/
7
+ .turbo/
8
+ .DS_Store
9
+ Thumbs.db
10
+ .idea/
11
+ .vscode/
12
+ *.log
13
+ .env
14
+ .env.local
15
+ .env.*.local
16
+ !.env.example
17
+ pnpm-debug.log*
18
+
19
+ # Claude Code worktrees and session scratch
20
+ .claude/
21
+ .tmp/
22
+
23
+ # Python bytecode
24
+ __pycache__/
25
+ *.pyc
26
+ *.pyo
27
+ *.pyd
28
+ .pytest_cache/
29
+
30
+ # Java build output
31
+ target/
32
+ *.class
33
+ *.jar
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: cnos-firebase
3
+ Version: 1.12.0
4
+ Summary: CNOS Firebase Secrets provider (thin wrapper over cnos-gcp)
5
+ Requires-Python: >=3.8
6
+ Requires-Dist: cnos-gcp>=1.12.0
7
+ Requires-Dist: cnos>=1.12.0
@@ -0,0 +1,19 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "cnos-firebase"
7
+ version = "1.12.0"
8
+ description = "CNOS Firebase Secrets provider (thin wrapper over cnos-gcp)"
9
+ requires-python = ">=3.8"
10
+ dependencies = [
11
+ "cnos>=1.12.0",
12
+ "cnos-gcp>=1.12.0",
13
+ ]
14
+
15
+ [tool.hatch.build.targets.wheel]
16
+ packages = ["src/cnos_firebase"]
17
+
18
+ [tool.pytest.ini_options]
19
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ """CNOS Firebase Secrets provider."""
2
+ from cnos_firebase.provider import FirebaseSecretsProvider, factory
3
+
4
+ __all__ = ["FirebaseSecretsProvider", "factory"]
@@ -0,0 +1,56 @@
1
+ """Firebase Secrets CNOS vault provider.
2
+
3
+ This is a thin wrapper over GcpSecretManagerProvider. Firebase projects use
4
+ the same GCP Secret Manager API; the only difference is the provider name
5
+ reported to the CNOS runtime ("firebase-secrets" instead of "gcp-secret-manager").
6
+
7
+ All authentication and secret-fetching logic is delegated entirely to
8
+ GcpSecretManagerProvider.
9
+ """
10
+ from __future__ import annotations
11
+
12
+ from typing import Any, Dict, List, Optional
13
+
14
+ from cnos.types import (
15
+ SecretVaultProvider,
16
+ SecretVaultProviderFactory,
17
+ VaultAuthConfig,
18
+ VaultDefinition,
19
+ )
20
+ from cnos_gcp.provider import GcpSecretManagerProvider
21
+
22
+ PROVIDER_NAME = "firebase-secrets"
23
+
24
+
25
+ class FirebaseSecretsProvider(SecretVaultProvider):
26
+ """Delegates entirely to GcpSecretManagerProvider; swaps the provider name."""
27
+
28
+ def __init__(
29
+ self,
30
+ vault_id: str,
31
+ definition: VaultDefinition,
32
+ client: Any = None,
33
+ ) -> None:
34
+ self._vault_id = vault_id
35
+ self._definition = definition
36
+ self._delegate = GcpSecretManagerProvider(vault_id, definition, client=client)
37
+
38
+ def authenticate(self, auth: VaultAuthConfig) -> None:
39
+ self._delegate.authenticate(auth)
40
+
41
+ def batch_get(self, refs: List[str]) -> Dict[str, Any]:
42
+ return self._delegate.batch_get(refs)
43
+
44
+ def get(self, ref: str) -> Optional[Any]:
45
+ return self._delegate.get(ref)
46
+
47
+
48
+ def factory(client: Any = None) -> SecretVaultProviderFactory:
49
+ """Return a SecretVaultProviderFactory for Firebase Secrets.
50
+
51
+ Pass client= to inject a mock GCP Secret Manager client for tests.
52
+ """
53
+ def create(vault_id: str, definition: VaultDefinition) -> FirebaseSecretsProvider:
54
+ return FirebaseSecretsProvider(vault_id, definition, client=client)
55
+
56
+ return SecretVaultProviderFactory(provider=PROVIDER_NAME, create=create)
File without changes
@@ -0,0 +1,135 @@
1
+ """Tests for the Firebase Secrets provider.
2
+
3
+ FirebaseSecretsProvider is a thin wrapper over GcpSecretManagerProvider;
4
+ all functional logic is tested in cnos-gcp. These tests verify:
5
+ - the provider name constant is "firebase-secrets"
6
+ - delegation to the GCP provider works end-to-end
7
+ - factory() returns a usable SecretVaultProviderFactory
8
+ """
9
+ from __future__ import annotations
10
+
11
+ from typing import Any, Dict, Optional
12
+
13
+ import pytest
14
+
15
+ from cnos.types import VaultAuthConfig, VaultAuthDefinition, VaultDefinition
16
+ from cnos_firebase.provider import FirebaseSecretsProvider, PROVIDER_NAME, factory
17
+
18
+
19
+ # ---------------------------------------------------------------------------
20
+ # Mock GCP Secret Manager client (reused from cnos-gcp tests)
21
+ # ---------------------------------------------------------------------------
22
+
23
+ class _NotFoundError(Exception):
24
+ pass
25
+
26
+
27
+ class MockGcpClient:
28
+ def __init__(self, secrets: Dict[str, str], project_id: str = "test-project") -> None:
29
+ self._secrets = secrets
30
+ self.project_id = project_id
31
+
32
+ def access_secret_version(self, name: str) -> str:
33
+ for key, val in self._secrets.items():
34
+ if key in name:
35
+ return val
36
+ raise _NotFoundError(f"not found: {name}")
37
+
38
+
39
+ def _make_provider(
40
+ secrets: Dict[str, str] = None,
41
+ project_id: str = "test-project",
42
+ mapping: dict = None,
43
+ ) -> FirebaseSecretsProvider:
44
+ definition = VaultDefinition(
45
+ provider=PROVIDER_NAME,
46
+ auth=VaultAuthDefinition(method="iam", config={"projectId": project_id}),
47
+ mapping=mapping or {},
48
+ )
49
+ client = MockGcpClient(secrets or {}, project_id=project_id)
50
+ p = FirebaseSecretsProvider("test-vault", definition, client=client)
51
+ p._delegate._authenticated = True
52
+ return p
53
+
54
+
55
+ # ---------------------------------------------------------------------------
56
+ # Tests
57
+ # ---------------------------------------------------------------------------
58
+
59
+ class TestProviderName:
60
+ def test_constant(self):
61
+ assert PROVIDER_NAME == "firebase-secrets"
62
+
63
+ def test_factory_provider_name(self):
64
+ f = factory()
65
+ assert f.provider == "firebase-secrets"
66
+
67
+
68
+ class TestAuthenticate:
69
+ def test_iam_accepted(self):
70
+ p = _make_provider()
71
+ p._delegate._authenticated = False
72
+ p.authenticate(VaultAuthConfig(method="iam"))
73
+ assert p._delegate._authenticated
74
+
75
+ def test_environment_accepted(self):
76
+ p = _make_provider()
77
+ p._delegate._authenticated = False
78
+ p.authenticate(VaultAuthConfig(method="environment"))
79
+ assert p._delegate._authenticated
80
+
81
+ def test_wrong_method_raises(self):
82
+ p = _make_provider()
83
+ p._delegate._authenticated = False
84
+ with pytest.raises(Exception, match="iam authentication"):
85
+ p.authenticate(VaultAuthConfig(method="token", token="t"))
86
+
87
+
88
+ class TestBatchGet:
89
+ def test_delegates_to_gcp(self):
90
+ p = _make_provider({"my-secret": "firebase-value"})
91
+ result = p.batch_get(["my-secret"])
92
+ assert result == {"my-secret": "firebase-value"}
93
+
94
+ def test_not_found_excluded(self):
95
+ p = _make_provider({})
96
+ result = p.batch_get(["missing"])
97
+ assert "missing" not in result
98
+
99
+ def test_multiple_secrets(self):
100
+ p = _make_provider({"s1": "v1", "s2": "v2"})
101
+ result = p.batch_get(["s1", "s2"])
102
+ assert result == {"s1": "v1", "s2": "v2"}
103
+
104
+
105
+ class TestGet:
106
+ def test_existing_secret(self):
107
+ p = _make_provider({"sec": "val"})
108
+ assert p.get("sec") == "val"
109
+
110
+ def test_missing_returns_none(self):
111
+ p = _make_provider({})
112
+ assert p.get("missing") is None
113
+
114
+
115
+ class TestMapping:
116
+ def test_external_mapping(self):
117
+ p = _make_provider(
118
+ {"firebase-project/external-name": "mapped-value"},
119
+ mapping={"firebase-project/external-name": "logical.key"},
120
+ )
121
+ result = p.batch_get(["logical.key"])
122
+ assert result.get("logical.key") == "mapped-value"
123
+
124
+
125
+ class TestFactory:
126
+ def test_factory_creates_provider(self):
127
+ client = MockGcpClient({"key": "val"})
128
+ definition = VaultDefinition(
129
+ provider=PROVIDER_NAME,
130
+ auth=VaultAuthDefinition(method="iam", config={"projectId": "proj"}),
131
+ )
132
+ f = factory(client=client)
133
+ p = f.create("my-vault", definition)
134
+ assert isinstance(p, FirebaseSecretsProvider)
135
+ assert f.provider == PROVIDER_NAME