fix: make dev tools executable
This commit is contained in:
@@ -3,7 +3,9 @@
|
||||
This directory supplies the ready-made `python` and `dotnet` scripts. They are not reserved:
|
||||
modify, replace, or remove them like any other script. Place other trusted executable install
|
||||
scripts here and add the desired file names to `AGENTCI_INSTALL_SCRIPTS`. Compose mounts the
|
||||
directory read-only at `/etc/agentci/install-scripts`.
|
||||
directory read-only at `/etc/agentci/install-scripts`. Executable files run directly; files without
|
||||
executable mode run as POSIX shell scripts through `/bin/sh` so bind mounts do not depend on host
|
||||
file-mode preservation.
|
||||
|
||||
Scripts run from the cloned repository with a sanitized environment. They receive:
|
||||
|
||||
@@ -19,4 +21,4 @@ not persist into implementation turns.
|
||||
The configured scripts run in list order after the repository is cloned (or an existing agent PR
|
||||
branch is synchronized) and before the first implementation turn for `implement`, `iterate`, and
|
||||
`fix`. They do not rerun between implementation and review-revision turns within one job. Scripts
|
||||
must be executable, idempotent, and must not expect AgentCI or Gitea credentials.
|
||||
must be idempotent and must not expect AgentCI or Gitea credentials.
|
||||
|
||||
@@ -55,19 +55,18 @@ class DevelopmentEnvironment:
|
||||
) from exc
|
||||
if resolved.parent != self.scripts_dir.resolve() or not resolved.is_file():
|
||||
raise DevelopmentEnvironmentError(f"Install script {name!r} is not a regular file")
|
||||
if not os.access(resolved, os.X_OK):
|
||||
raise DevelopmentEnvironmentError(f"Install script {name!r} is not executable")
|
||||
return resolved
|
||||
|
||||
async def _run(self, name: str, script: Path, workspace: Path) -> None:
|
||||
started = monotonic()
|
||||
command = [str(script)] if os.access(script, os.X_OK) else ["/bin/sh", str(script)]
|
||||
log.info(
|
||||
"development install script started",
|
||||
extra={"operation": "development.install", "script": name},
|
||||
)
|
||||
try:
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
str(script),
|
||||
*command,
|
||||
cwd=workspace,
|
||||
env=self._environment(),
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
|
||||
@@ -61,6 +61,19 @@ async def test_supplied_script_names_use_the_same_directory(tmp_path) -> None:
|
||||
assert (workspace / "selected").read_text() == "python\n"
|
||||
|
||||
|
||||
async def test_runs_non_executable_shell_script_from_bind_mount(tmp_path) -> None:
|
||||
workspace = tmp_path / "workspace"
|
||||
workspace.mkdir()
|
||||
development = environment(tmp_path, ["mounted"])
|
||||
mounted = development.scripts_dir / "mounted"
|
||||
mounted.write_text("#!/bin/sh\nprintf 'mounted\\n' > selected\n")
|
||||
mounted.chmod(0o644)
|
||||
|
||||
await development.prepare(workspace)
|
||||
|
||||
assert (workspace / "selected").read_text() == "mounted\n"
|
||||
|
||||
|
||||
async def test_reports_script_failure_output(tmp_path) -> None:
|
||||
workspace = tmp_path / "workspace"
|
||||
workspace.mkdir()
|
||||
|
||||
Reference in New Issue
Block a user