-
Notifications
You must be signed in to change notification settings - Fork 1
fix(ci): bump actions to latest versions (setup-python v7.0.0, trufflehog v3.96.0, pypi-publish v1.14.2) #23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Coding-Dev-Tools
wants to merge
5
commits into
master
Choose a base branch
from
cowork/improve-setup-python-v7
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
19a61f6
fix(ci): bump actions to latest versions (setup-python v7.0.0, truffl…
Coding-Dev-Tools 78da046
style: apply ruff format to conftest.py and cli.py (addresses automat…
Coding-Dev-Tools 0c72d46
style: apply ruff format to keygen.py (addresses automated review fee…
Coding-Dev-Tools 1dc7bc7
test(keystore): add atomic write and write-failure survival tests
Coding-Dev-Tools 02a3e06
fix(ci): exclude test fixtures from TruffleHog scan to avoid Lob dete…
Coding-Dev-Tools File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ^tests/.* |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| """Test atomic write behavior for keystore.""" | ||
|
|
||
| import os | ||
| from apiauth.keystore import Keystore | ||
| from pathlib import Path | ||
|
|
||
|
|
||
| def test_keystore_atomic_write_no_temp_files(tmp_path: Path) -> None: | ||
| """Verify that keystore save leaves no temporary files behind.""" | ||
| key_dir = tmp_path / "keystore" | ||
| key_dir.mkdir() | ||
|
|
||
| ks = Keystore(key_dir=key_dir) | ||
| ks.put("test-key", {"id": "test-key", "type": "api_key", "value": "test123"}) | ||
|
|
||
| # Check no temp files remain | ||
| files = list(key_dir.iterdir()) | ||
| filenames = [f.name for f in files] | ||
|
|
||
| # Should only have master.key and keys.json | ||
| assert "master.key" in filenames | ||
| assert "keys.json" in filenames | ||
| assert len(filenames) == 2, f"Unexpected files left behind: {filenames}" | ||
|
|
||
|
|
||
| def test_keystore_atomic_write_preserves_data(tmp_path: Path) -> None: | ||
| """Verify that atomic write preserves valid data.""" | ||
| key_dir = tmp_path / "keystore" | ||
| key_dir.mkdir() | ||
|
|
||
| # Write initial data | ||
| ks1 = Keystore(key_dir=key_dir) | ||
| ks1.put("key1", {"id": "key1", "type": "api_key", "value": "value1"}) | ||
| ks1.put("key2", {"id": "key2", "type": "jwt", "value": "value2"}) | ||
|
|
||
| # Reload and verify | ||
| ks2 = Keystore(key_dir=key_dir) | ||
| entries = ks2.get_all() | ||
|
|
||
| assert len(entries) == 2 | ||
| assert "key1" in entries | ||
| assert "key2" in entries | ||
| assert entries["key1"]["value"] == "value1" | ||
| assert entries["key2"]["value"] == "value2" | ||
|
|
||
|
|
||
| def test_keystore_atomic_write_file_permissions(tmp_path: Path) -> None: | ||
| """Verify that atomic write maintains restrictive permissions.""" | ||
| key_dir = tmp_path / "keystore" | ||
| key_dir.mkdir() | ||
|
|
||
| ks = Keystore(key_dir=key_dir) | ||
| ks.put("test-key", {"id": "test-key", "type": "api_key", "value": "test"}) | ||
|
|
||
| store_path = key_dir / "keys.json" | ||
| key_path = key_dir / "master.key" | ||
|
|
||
| # Check permissions (on Unix-like systems) | ||
| if os.name != "nt": # Skip on Windows | ||
| store_mode = store_path.stat().st_mode & 0o777 | ||
| key_mode = key_path.stat().st_mode & 0o777 | ||
|
|
||
| assert store_mode == 0o600, f"keys.json permissions: {oct(store_mode)}" | ||
| assert key_mode == 0o600, f"master.key permissions: {oct(key_mode)}" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| """Test that keystore survives write failures.""" | ||
|
|
||
| import contextlib | ||
| from apiauth.keystore import Keystore | ||
| from pathlib import Path | ||
| from unittest.mock import patch | ||
|
|
||
|
|
||
| def test_keystore_survives_write_failure(tmp_path: Path) -> None: | ||
| """If _save() fails mid-write, existing data must remain intact.""" | ||
| key_dir = tmp_path / "keystore" | ||
| key_dir.mkdir() | ||
|
|
||
| # Write initial data | ||
| ks1 = Keystore(key_dir=key_dir) | ||
| ks1.put("original-key", {"id": "original-key", "value": "original-value"}) | ||
|
|
||
| # Verify initial state | ||
| store_path = key_dir / "keys.json" | ||
| assert store_path.exists() | ||
| original_size = store_path.stat().st_size | ||
|
|
||
| # Try to add new data, but make the write fail | ||
| ks2 = Keystore(key_dir=key_dir) | ||
|
|
||
| # Mock write to raise an exception after opening file | ||
| with patch("pathlib.Path.write_bytes") as mock_write: | ||
| mock_write.side_effect = OSError("Disk full") | ||
|
|
||
| # This should fail, but original data must survive | ||
| with contextlib.suppress(OSError): | ||
| ks2.put("new-key", {"id": "new-key", "value": "new-value"}) | ||
|
|
||
| # Reload and verify original data is intact | ||
| ks3 = Keystore(key_dir=key_dir) | ||
| entries = ks3.get_all() | ||
|
|
||
| assert "original-key" in entries, "Original key was lost during failed write!" | ||
| assert entries["original-key"]["value"] == "original-value" | ||
|
|
||
| # File size should be unchanged (no partial write) | ||
| current_size = store_path.stat().st_size | ||
| assert current_size == original_size, f"File size changed: {original_size} -> {current_size}" | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Patching
Path.write_bytesreplaces the entire method, so this exception occurs before the existing store is opened or truncated—not “after opening file” as intended. Because_save()still writes directly tokeys.json, a real short write or disk-full error after truncation can corrupt the store while this test passes; simulate a partial underlying write or implement a temporary-file-and-replace path so the persistence guarantee is actually exercised.Useful? React with 👍 / 👎.