Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
pull_request:

env:
BASE_IMAGE_REVISION: r3
BASE_IMAGE_REVISION: r4

jobs:
build:
Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-include env_make

# Accept legacy build arguments during the image revision transition.
BASE_IMAGE_REVISION ?= $(BASE_IMAGE_STABILITY_TAG)
BASE_IMAGE_REVISION ?= $(if $(BASE_IMAGE_STABILITY_TAG),$(BASE_IMAGE_STABILITY_TAG),r4)

PHP_VER ?= 8.5

Expand Down Expand Up @@ -67,7 +67,11 @@ buildx-imagetools-create:
.PHONY: buildx-imagetools-create

test:
IMAGE=$(REPO):$(TAG) bash tests/workspace-contract.sh
docker run --rm --network none --entrypoint /bin/bash -e DRUPAL_VERSION=11 -v "$(CURDIR)/tests/workspace-image-runtime.sh:/tmp/workspace-image-runtime.sh:ro" $(REPO):$(TAG) /tmp/workspace-image-runtime.sh
bash tests/runtime-configuration.sh
bash tests/workspace-checkout.sh
docker run --rm --network none --entrypoint /docker-entrypoint.sh -e DRUPAL_VERSION=11 $(REPO):$(TAG) --configure-runtime
docker run --rm --network none --user root \
-v "$(CURDIR)/tests/asset-permissions.sh:/tmp/asset-permissions.sh:ro" \
$(REPO):$(TAG) bash /tmp/asset-permissions.sh
Expand Down
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,27 @@ image. A version without a pin fails before the build starts.
When adding a supported base version or variant, add its image index digest to
`base-images.mk`. For a custom build, override `BASE_IMAGE` with a complete
`repository:tag@sha256:...` reference.

### Workspace preparation and Git

With `WODBY_WORKSPACE=1`, initialization preflights settings and upload paths before
changing the checkout. It refuses to append configuration to tracked settings or
replace tracked upload files. Generated settings must be ignored and untracked;
ignoring an already tracked file alone is insufficient.

For tracked settings, add the bootstrap include deliberately and commit it with
application configuration. For example, in `settings.php`:

```php
$wodbyConfig = (getenv('CONF_DIR') ?: '/var/www/conf') . '/wodby.settings.php';
if (is_file($wodbyConfig)) {
include $wodbyConfig;
}
```

Multisite projects need the equivalent `wodby.sites.php` include in `sites/sites.php`.
Keep uploaded files and generated local settings out of Git. Retry preparation after
fixing the reported paths. Standard initialization retains its existing behavior.
Dependency managers and project scripts can still change source files; inspect the
Git diff before committing. Inherited workspace support requires a PHP base image
that declares workspace contract version 1.
13 changes: 13 additions & 0 deletions base-images.mk
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,16 @@ BASE_IMAGE_DIGEST_8.5-dev-macos-r3 := sha256:37efa836179df64abda61e401750fdd3d35

# Fail before building when a version or variant has no reviewed pin.
BASE_IMAGE = $(BASE_IMAGE_REPOSITORY):$(BASE_IMAGE_TAG)@$(or $(BASE_IMAGE_DIGEST_$(BASE_IMAGE_TAG)),$(error No base image digest for $(BASE_IMAGE_REPOSITORY):$(BASE_IMAGE_TAG); update base-images.mk))

BASE_IMAGE_DIGEST_8.2-r4 := sha256:c374f68216ff78ce766e93e02fd3faa90cb5c9ae5db5b12a747533ddfae5b4e0
BASE_IMAGE_DIGEST_8.2-dev-r4 := sha256:4c22a51a81c328e29f42a4fc67210f7762a411a9a0638624e80d342b05940a35
BASE_IMAGE_DIGEST_8.2-dev-macos-r4 := sha256:bfdad65b9efc8a5baa3fd7f373c3edcccf1953d34f5ad088e66ccb171278d161
BASE_IMAGE_DIGEST_8.3-r4 := sha256:20f41bfaecae7d7e29b76bb90d0eb4bbf582b1a21e35af2d4dcc81c15182c56a
BASE_IMAGE_DIGEST_8.3-dev-r4 := sha256:24dc62dbdaca5b7c31ae2ce244b50b537cbf7b10b68c3397edbe2b35bed0cfb8
BASE_IMAGE_DIGEST_8.3-dev-macos-r4 := sha256:4bf12cf98108e2a8afc9049756041f45e6f1dabf2f34965c63272f2c75b802c9
BASE_IMAGE_DIGEST_8.4-r4 := sha256:f3d719311664ba6e9d061a8667de3bddd9ccba1cd858a8f9896adb234d3be321
BASE_IMAGE_DIGEST_8.4-dev-r4 := sha256:55041fd0bc5fbcfb857d6fd908c2a9c109b0a1f1a1bea5345f8c0c52978845e4
BASE_IMAGE_DIGEST_8.4-dev-macos-r4 := sha256:6fcdb77452be58c1b834b6278feea00cc72a021783862bf9013d3ad7eaeee872
BASE_IMAGE_DIGEST_8.5-r4 := sha256:9fa803b8e5def413753a9869c310f1e793d0d6da5fc91cb54ffb2be7b76edd94
BASE_IMAGE_DIGEST_8.5-dev-r4 := sha256:9227547ca9d7ef6d7eb31f7bd06b2aba31c9605a0a984b0726d3c2f3e9bc92b3
BASE_IMAGE_DIGEST_8.5-dev-macos-r4 := sha256:8fbe0b190d93e3f9fd7084ba1e713cbd6a8f9bec2675ac2dd78daf9a7a710534
28 changes: 28 additions & 0 deletions bin/init_drupal
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,34 @@ settings_php="${DRUPAL_SITE_DIR}/settings.php"
default_settings_php="${DRUPAL_SITE_DIR}/default.settings.php"
sites_php="${DRUPAL_ROOT}/sites/sites.php"

# A workspace checkout belongs to the developer. Preflight every generated path
# before making any changes; only ignored, untracked paths may be generated.
if [[ "${WODBY_WORKSPACE:-}" == 1 ]]; then
root=$(git -C "${APP_ROOT}" rev-parse --show-toplevel) || exit 1
workspace_generated_path() {
local target relative tracked
target="$(cd "$(dirname "$1")" && pwd -P)/$(basename "$1")" || return 1
if [[ -L "$1" ]]; then target=$(realpath "$1") || return 1; fi
case "$target" in "$root"/*) relative="${target#"$root"/}" ;; *)
echo "Workspace setup refuses to modify a path outside the checkout: $1" >&2; return 1 ;;
esac
tracked=$(git -C "$root" ls-files -- "$relative") || return 1
if [[ -n "$tracked" ]] || ! git -C "$root" check-ignore -q -- "$relative"; then
echo "Workspace setup would change $relative. Add the required Wodby settings include explicitly, or ignore this generated path and remove it from Git tracking before retrying preparation." >&2
return 1
fi
}
if [[ ! -f "$settings_php" ]] || ! grep -qi 'wodby.settings.php' "$settings_php"; then
workspace_generated_path "$settings_php"
fi
if [[ "${DRUPAL_SITE}" != default ]] && { [[ ! -f "$sites_php" ]] || ! grep -qi 'wodby.sites.php' "$sites_php"; }; then
workspace_generated_path "$sites_php"
fi
if [[ ! -L "${DRUPAL_SITE_DIR}/files" ]]; then
workspace_generated_path "${DRUPAL_SITE_DIR}/files"
fi
fi

mkdir -p "${DRUPAL_SITE_DIR}"
chmod 755 "${DRUPAL_SITE_DIR}" || true

Expand Down
40 changes: 40 additions & 0 deletions tests/workspace-checkout.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env bash
# Run without Drupal installed; real Git tracking rules guard all mutations.
set -euo pipefail
script="$(cd "$(dirname "$0")/.." && pwd)/bin/init_drupal"
fixture=$(mktemp -d)
trap 'rm -rf "$fixture"' EXIT
export APP_ROOT="$fixture" DRUPAL_ROOT="$fixture/web" DRUPAL_SITE=default
export DRUPAL_SITE_DIR="$DRUPAL_ROOT/sites/default" CONF_DIR=/var/www/conf FILES_DIR="$fixture/uploads" WODBY_WORKSPACE=1 DEBUG=''
mkdir -p "$DRUPAL_SITE_DIR" "$fixture/bin"
printf '#!/bin/sh\n[ -L "$1" ] || ln -s "$FILES_DIR/public" "$1"\n' > "$fixture/bin/files_link"
chmod +x "$fixture/bin/files_link"
export PATH="$fixture/bin:$PATH"
git -C "$fixture" init -q
printf '<?php\n// customer settings\n' > "$DRUPAL_SITE_DIR/settings.php"
printf 'web/sites/default/files\n' > "$fixture/.gitignore"
git -C "$fixture" add .gitignore web/sites/default/settings.php
before=$(git -C "$fixture" diff --binary)
if bash "$script" > "$fixture/error" 2>&1; then echo 'Modified tracked settings' >&2; exit 1; fi
test "$before" = "$(git -C "$fixture" diff --binary)"
test ! -L "$DRUPAL_SITE_DIR/files"
grep -q 'Add the required Wodby settings include' "$fixture/error"
# Explicitly configured tracked settings are left byte-for-byte unchanged.
printf "<?php\ninclude '/var/www/conf/wodby.settings.php';\n" > "$DRUPAL_SITE_DIR/settings.php"
git -C "$fixture" add web/sites/default/settings.php
bash "$script"
test -z "$(git -C "$fixture" diff --binary)"
# Missing settings can be generated only when ignored and untracked.
git -C "$fixture" rm --cached -q web/sites/default/settings.php
rm "$DRUPAL_SITE_DIR/settings.php"
if bash "$script" > "$fixture/error" 2>&1; then echo 'Generated visible settings' >&2; exit 1; fi
printf 'web/sites/default/settings.php\n' >> "$fixture/.gitignore"
bash "$script"
grep -q wodby.settings.php "$DRUPAL_SITE_DIR/settings.php"
# Tracked upload placeholders must never be removed, even if .gitignored.
rm "$DRUPAL_SITE_DIR/files"
mkdir "$DRUPAL_SITE_DIR/files"
printf '*' > "$DRUPAL_SITE_DIR/files/.gitignore"
git -C "$fixture" add -f web/sites/default/files/.gitignore
if bash "$script" > "$fixture/error" 2>&1; then echo 'Replaced tracked uploads' >&2; exit 1; fi
test -f "$DRUPAL_SITE_DIR/files/.gitignore"
9 changes: 9 additions & 0 deletions tests/workspace-contract.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# Ensure ordinary images do not advertise the development-only contract.
set -euo pipefail
label=$(docker image inspect --format '{{index .Config.Labels "com.wodby.workspace.contract"}}' "$IMAGE")
if docker image inspect --format '{{range .Config.Env}}{{println .}}{{end}}' "$IMAGE" | grep -Eq '^PHP_DEV=.+$'; then
test "$label" = 1
else
test -z "$label"
fi
27 changes: 27 additions & 0 deletions tests/workspace-image-runtime.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
# Run inside a fresh PHP container, with its normal entrypoint bypassed.
set -euo pipefail
mkdir -p "$HOME/.ssh"
printf '# custom SSH config\n' > "$HOME/.ssh/config"
printf '[user]\n\tname = Developer\n' > "$HOME/.gitconfig"
ssh_before=$(sha256sum "$HOME/.ssh/config")
git_before=$(sha256sum "$HOME/.gitconfig")
export PHP_CLI_MEMORY_LIMIT=321M
# Configuration must not execute a checkout action, even when one is configured.
export WODBY2_SERVICE_INIT_ACTION=nonexistent-workspace-test-action
/docker-entrypoint.sh --configure-runtime
test "$(php -r 'echo ini_get("memory_limit");')" = 321M
test "$(sha256sum "$HOME/.ssh/config")" = "$ssh_before"
test "$(sha256sum "$HOME/.gitconfig")" = "$git_before"
/docker-entrypoint.sh --configure-runtime
test "$(sha256sum "$HOME/.ssh/config")" = "$ssh_before"

# Live code must be revalidated even when production disabled timestamp checks.
export WODBY_WORKSPACE=1 PHP_OPCACHE_VALIDATE_TIMESTAMPS=0 PHP_OPCACHE_REVALIDATE_FREQ=60
/docker-entrypoint.sh --configure-runtime
test "$(php -r 'echo ini_get("opcache.validate_timestamps");')" = 1
test "$(php -r 'echo ini_get("opcache.revalidate_freq");')" = 0
unset WODBY_WORKSPACE
/docker-entrypoint.sh --configure-runtime
test "$(php -r 'echo ini_get("opcache.validate_timestamps");')" = 0
test "$(php -r 'echo ini_get("opcache.revalidate_freq");')" = 60