feat(resolve): warn that apply cannot enable "Include Source Commit in Build"
Coolify 4.1.2 gates the SOURCE_COMMIT *build arg* behind a per-application
setting (ApplicationSetting.include_source_commit_in_build, default false)
that has no API surface: it appears in zero API controllers, and both the
create (l.914) and PATCH (l.2368) allowlists in ApplicationsController.php
reject unrecognized keys outright ("This field is not allowed."), so it
cannot be smuggled through — sending it would 422 the whole request. Its
only writer in v4.1.2 is the Livewire Advanced tab (Advanced.php:128), i.e.
a human in the UI.
So apply says it out loud, once per dockercompose application, via the same
desiredFromManifest mechanism and in the same voice as the existing umami
service-domains warning. A manual step the tool knows about and does not
mention is a manual step that gets forgotten — and this one fails green.
Note the toggle gates the BUILD-time arg only; Coolify's runtime injection
of SOURCE_COMMIT is unconditional (ApplicationDeploymentJob.php:2949), so
a service reading process.env.SOURCE_COMMIT per request never needed it.
The warning therefore does not repeat #46's original (incorrect) premise
that this toggle is why /version reported sha "unknown" — the real cause is
an app-level env var suppressing Coolify's own injection (#50).
Closes #46.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
7cc3a3b64e
commit
93bca37890
3 changed files with 107 additions and 0 deletions
|
|
@ -624,6 +624,33 @@ one used — verified against a live private clone.
|
|||
Coolify 4.1.2 services — configure hostnames manually in the Coolify UI`)
|
||||
once per run for every service that declared any. Set service hostnames
|
||||
in the Coolify UI by hand.
|
||||
- **"Include Source Commit in Build" cannot be enabled via the API in Coolify
|
||||
4.1.2 — `apply` warns instead.** A dockercompose application whose build
|
||||
consumes `SOURCE_COMMIT` as a **build arg** only receives it if the
|
||||
per-application setting *Include Source Commit in Build* is on; Coolify
|
||||
withholds it by default to preserve build cache. That setting
|
||||
(`ApplicationSetting.include_source_commit_in_build`, default `false`) has no
|
||||
API surface in 4.1.2: it appears in **zero** API controllers, and both the
|
||||
create and PATCH allowlists in `ApplicationsController.php` (l.914, l.2368)
|
||||
reject unrecognized keys outright (`"This field is not allowed."`), so cast
|
||||
cannot smuggle it through — sending it would fail the whole request. Its only
|
||||
writer is the Livewire *Advanced* tab
|
||||
(`app/Livewire/Project/Application/Advanced.php:128`), i.e. a human in the UI.
|
||||
Contrast `connect_to_docker_network`, which *is* in both allowlists and which
|
||||
`apply` therefore does set on create. So `desiredFromManifest` **warns** once
|
||||
per dockercompose application (`application <name> builds with dockercompose,
|
||||
but apply cannot enable "Include Source Commit in Build" on Coolify 4.1.2 …`)
|
||||
rather than pretending it is desired state. Enable it in the Coolify UI and
|
||||
redeploy if your image bakes the SHA in at build time.
|
||||
|
||||
**This toggle gates the build-time arg only.** Coolify's **runtime** injection
|
||||
of `SOURCE_COMMIT` is unconditional with respect to it
|
||||
(`ApplicationDeploymentJob.php:2949` — `if (! $forBuildTime || …)`
|
||||
short-circuits true at runtime), so a service that reads
|
||||
`process.env.SOURCE_COMMIT` per request does **not** need the toggle at all.
|
||||
What silently suppresses *that* value is an application-level env var of the
|
||||
same name (`ApplicationDeploymentJob.php:2950`) — a distinct trap, and the
|
||||
actual cause of a live box reporting `{"sha":"unknown"}`.
|
||||
- **The redis default image is an unverified extrapolation.** Coolify's
|
||||
"New Resource" wizard drives PostgreSQL version selection through a
|
||||
verified `postgres:<version>-alpine` image string; Redis has no version
|
||||
|
|
|
|||
|
|
@ -345,6 +345,34 @@ export function desiredFromManifest(
|
|||
return env;
|
||||
};
|
||||
for (const [name, app] of Object.entries(envSpec.applications)) {
|
||||
if (app.build.pack === "dockercompose") {
|
||||
// Coolify gates the SOURCE_COMMIT *build arg* behind a per-application
|
||||
// setting — `ApplicationSetting.include_source_commit_in_build`, default
|
||||
// false — and in 4.1.2 that setting has NO API surface. Verified against
|
||||
// the v4.1.2 source: it appears in zero API controllers, and both the
|
||||
// create and the PATCH allowlists in ApplicationsController.php (l.914,
|
||||
// l.2368) reject unrecognized keys outright ("This field is not
|
||||
// allowed."), so sending it would fail the whole request rather than be
|
||||
// quietly ignored. Its only writer is the Livewire Advanced tab
|
||||
// (app/Livewire/Project/Application/Advanced.php:128) — i.e. a human, in
|
||||
// the UI. Do NOT add it to `fields` below expecting apply to set it the
|
||||
// way it sets `connect_to_docker_network` (which *is* in the allowlist,
|
||||
// which is why that one works): apply would 422 on every run. Warning is
|
||||
// the only honest move — a manual step the tool knows about and does not
|
||||
// mention is one that gets forgotten, and this one fails green.
|
||||
//
|
||||
// Scope: the toggle gates the BUILD-time arg only. Coolify's *runtime*
|
||||
// injection of SOURCE_COMMIT is unconditional with respect to it
|
||||
// (ApplicationDeploymentJob.php:2949 — `if (! $forBuildTime || ...)`,
|
||||
// which short-circuits true at runtime), so a service that reads
|
||||
// process.env.SOURCE_COMMIT per request does not need this toggle at all.
|
||||
// What *does* silently suppress that runtime value is an application-level
|
||||
// env var of the same name (ApplicationDeploymentJob.php:2950) — a
|
||||
// different bug, tracked separately.
|
||||
console.warn(
|
||||
`application ${name} builds with dockercompose, but apply cannot enable "Include Source Commit in Build" on Coolify 4.1.2 — the setting is absent from the API's field allowlist. If the build consumes SOURCE_COMMIT as a build arg, enable it in the Coolify UI and redeploy; Coolify injects SOURCE_COMMIT at runtime regardless.`,
|
||||
);
|
||||
}
|
||||
desired.push({
|
||||
kind: "application",
|
||||
name,
|
||||
|
|
|
|||
|
|
@ -305,7 +305,9 @@ environments:
|
|||
join(dir, ".infra", "env", "core.prod.env.template"),
|
||||
"PORT=3000\n",
|
||||
);
|
||||
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
||||
const { desired } = desiredFromManifest(dir, "prod", {});
|
||||
warn.mockRestore();
|
||||
expect(desired).toHaveLength(1);
|
||||
expect(desired[0]).toMatchObject({
|
||||
kind: "application",
|
||||
|
|
@ -325,6 +327,56 @@ environments:
|
|||
expect(desired[0].fields).not.toHaveProperty("healthcheck");
|
||||
expect(desired[0].fields).not.toHaveProperty("domains");
|
||||
});
|
||||
it('warns that apply cannot enable "Include Source Commit in Build" on a dockercompose app (unsettable via the Coolify 4.1.2 API)', () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "infra-co-"));
|
||||
mkdirSync(join(dir, ".infra"), { recursive: true });
|
||||
writeFileSync(
|
||||
join(dir, ".infra", "manifest.yaml"),
|
||||
`project: widget
|
||||
environments:
|
||||
prod:
|
||||
applications:
|
||||
core:
|
||||
source: { repo: acme/widget, branch: main }
|
||||
build: { pack: dockercompose, base_directory: /, compose_file: docker-compose.yaml }
|
||||
service_domains:
|
||||
api: ["https://api.widget.example.com"]
|
||||
`,
|
||||
);
|
||||
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
||||
const { desired } = desiredFromManifest(dir, "prod", {});
|
||||
expect(warn).toHaveBeenCalledTimes(1);
|
||||
expect(warn.mock.calls[0][0]).toMatch(/application core/);
|
||||
expect(warn.mock.calls[0][0]).toMatch(/Include Source Commit in Build/);
|
||||
expect(warn.mock.calls[0][0]).toMatch(/Coolify UI/);
|
||||
warn.mockRestore();
|
||||
// The setting is absent from Coolify 4.1.2's create/PATCH allowlists, which
|
||||
// reject unknown keys outright — so it must never reach `fields`, or apply
|
||||
// would 422 on every run. Guards the fix a future reader would reach for.
|
||||
expect(desired[0].fields).not.toHaveProperty(
|
||||
"include_source_commit_in_build",
|
||||
);
|
||||
});
|
||||
it("does not warn about the source-commit toggle for a non-dockercompose app (the build arg is a compose concern)", () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "infra-co-"));
|
||||
mkdirSync(join(dir, ".infra"), { recursive: true });
|
||||
writeFileSync(
|
||||
join(dir, ".infra", "manifest.yaml"),
|
||||
`project: widget
|
||||
environments:
|
||||
prod:
|
||||
applications:
|
||||
site:
|
||||
source: { repo: acme/widget, branch: main }
|
||||
build: { pack: nixpacks, base_directory: / }
|
||||
domains: ["https://widget.example.com"]
|
||||
`,
|
||||
);
|
||||
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
||||
desiredFromManifest(dir, "prod", {});
|
||||
expect(warn).not.toHaveBeenCalled();
|
||||
warn.mockRestore();
|
||||
});
|
||||
it("throws when the env is missing from the manifest", () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "infra-co-"));
|
||||
mkdirSync(join(dir, ".infra"), { recursive: true });
|
||||
|
|
|
|||
Loading…
Reference in a new issue