This is an automated email from the ASF dual-hosted git repository.
sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
The following commit(s) were added to refs/heads/main by this push:
new 6cd3688 Disallow writing to release files after staging
6cd3688 is described below
commit 6cd36889ef90e616092d9a4b8c9ca2c1009d33c6
Author: Sean B. Palmer <[email protected]>
AuthorDate: Tue Jan 20 17:04:38 2026 +0000
Disallow writing to release files after staging
---
atr/server.py | 21 +++++++++++++++++++++
atr/storage/writers/revision.py | 7 +++++++
2 files changed, 28 insertions(+)
diff --git a/atr/server.py b/atr/server.py
index b52bcfe..cd76bf9 100644
--- a/atr/server.py
+++ b/atr/server.py
@@ -238,6 +238,8 @@ def _app_setup_lifecycle(app: base.QuartApp) -> None:
if listener := app.extensions.get("logging_listener"):
listener.start()
+ await asyncio.to_thread(_set_file_permissions_to_read_only)
+
worker_manager = manager.get_worker_manager()
await worker_manager.start()
@@ -706,6 +708,25 @@ def _register_routes(app: base.QuartApp) -> None:
return await template.render("notfound.html", error="404 Not Found",
traceback="", status_code=404), 404
+def _set_file_permissions_to_read_only() -> None:
+ """Set permissions of all files in the unfinished and finished directories
to read only."""
+ # TODO: After a migration period, incorrect permissions should be an error
+ directories = [util.get_unfinished_dir(), util.get_finished_dir()]
+ fixed_count = 0
+ for directory in directories:
+ if not directory.exists():
+ continue
+ for file_path in directory.rglob("*"):
+ if not file_path.is_file():
+ continue
+ mode = stat.S_IMODE(file_path.stat().st_mode)
+ if mode != 0o444:
+ os.chmod(file_path, 0o444)
+ fixed_count += 1
+ if fixed_count > 0:
+ log.info(f"Set permissions of {fixed_count} files to read only
(0o444)")
+
+
def _validate_config(app_config: type[config.AppConfig], hot_reload: bool) ->
None:
# Custom configuration for the database path is no longer supported
configured_path = app_config.SQLITE_DB_PATH
diff --git a/atr/storage/writers/revision.py b/atr/storage/writers/revision.py
index ddc89e5..f7037c6 100644
--- a/atr/storage/writers/revision.py
+++ b/atr/storage/writers/revision.py
@@ -157,6 +157,13 @@ class CommitteeParticipant(FoundationCommitter):
await aioshutil.rmtree(temp_dir)
raise
+ # Make files read only to prevent them from being modified through
hard links
+ try:
+ await asyncio.to_thread(util.chmod_files, temp_dir_path, 0o444)
+ except Exception:
+ await aioshutil.rmtree(temp_dir)
+ raise
+
async with SafeSession(temp_dir) as data:
try:
# This is the only place where models.Revision is constructed
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]