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
43 changes: 41 additions & 2 deletions .github/actions/test/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ description: >
Correction (aviorstudio/fieldsofrevik#148): the earlier text said this one
definition guarded release, but the GD release bypassed it and this action
omitted the shipped JavaScript suite. CI and Release now call this action,
which runs Go, Godot, JavaScript, runner controls, and the exact GD package
lifecycle gate.
which runs Go, Godot, JavaScript, runner controls, the exact GD package
lifecycle gate, and ordinary/diagnostic release-export browser checks.

A per-repo copy, not a shared action. `uses: ./` is repo-local, so the
fourteen copies of this file are copies -- the accepted cost of no repo's CI
Expand Down Expand Up @@ -83,3 +83,42 @@ runs:
- name: Install exact ZIP and verify editor lifecycle
shell: bash
run: bash gd/tests/package_lifecycle_test.sh dist/@aviorstudio_gd-playwright.zip

- name: Install verified Godot web export templates
shell: bash
run: |
set -euo pipefail
archive="$RUNNER_TEMP/Godot_v4.7.2-stable_export_templates.tpz"
unpack="$RUNNER_TEMP/gd-playwright-export-templates"
destination="${XDG_DATA_HOME:-$HOME/.local/share}/godot/export_templates/4.7.2.stable"
curl --fail --location --retry 3 --max-time 300 \
https://github.com/godotengine/godot-builds/releases/download/4.7.2-stable/Godot_v4.7.2-stable_export_templates.tpz \
--output "$archive"
printf '%s %s\n' 'ca4d71c4d7b81dfc15d1a98baa07534aa95b03fdda78a0075b06672e1648d2e5f40980c9adc28d23e1b92e732ee7bf3461997aa804af74ec2fcd7a93ccb84079' "$archive" | sha512sum --check
rm -rf "$unpack" "$destination"
mkdir -p "$unpack" "$destination"
unzip -q "$archive" -d "$unpack"
cp -a "$unpack/templates/." "$destination/"
test -s "$destination/web_release.zip"

- name: Install pinned Playwright CLI and Chromium
shell: bash
run: |
set -euo pipefail
npm install --global @playwright/cli@0.1.18
npx --yes playwright@1.63.0-alpha-2026-08-05 install --with-deps chromium
test "$(playwright-cli --version)" = "0.1.18"

- name: Verify ordinary and diagnostic web release artifacts
shell: bash
env:
GD_WEB_OUTPUT_DIR: ${{ github.workspace }}/dist/web-export-evidence
run: bash gd/tests/web_export_test.sh dist/@aviorstudio_gd-playwright.zip

- name: Upload web release acceptance evidence
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: gd-web-evidence-${{ github.run_id }}-${{ github.job }}
path: dist/web-export-evidence/
if-no-files-found: error
retention-days: 30
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: CI
# Every pull request and every merge to main: test, on one runner.
#
# The common action runs every shipped suite and verifies the exact assembled GD
# release ZIP through clean editor enable/restart/disable/restart lifecycle.
# release ZIP through clean editor lifecycle and ordinary/diagnostic web exports.

on:
pull_request:
Expand All @@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
# Bounded, so a step that hangs fails here rather than sitting until the
# runner's own timeout hours later.
timeout-minutes: 20
timeout-minutes: 30
steps:
# Third-party actions are pinned by SHA, with the tag in a trailing
# comment so the version is still readable. A tag is a moving reference:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
permissions:
contents: read
runs-on: ubuntu-latest
timeout-minutes: 20
timeout-minutes: 30
outputs:
tag: ${{ steps.release.outputs.tag }}
version: ${{ steps.release.outputs.version }}
Expand Down
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,27 @@ The Godot addon writes generic browser globals during enabled web runs:

## Safety Notes

- Features only run in web builds when debug mode, `enabled`, or `test_mode` is active. The production-export choice remains tracked by [fieldsofrevik#148](https://github.com/aviorstudio/fieldsofrevik/issues/148); this release does not choose between excluding diagnostics and a dedicated production automation feature.
- Debug web builds retain the existing `enabled`/`test_mode` behavior. Ordinary release exports never create gd-playwright browser globals, even when those settings are enabled.
- Production diagnostics require a separate export preset with the custom feature `gd_playwright_diagnostics`. Configure `PlaywrightConfig` with a `PlaywrightPayloadPolicy`: exact element keys and prefixes, event-name to allowed-field rules, and state-namespace to allowed-field rules. Empty or missing rules deny publication.
- Diagnostic release payloads must contain only JSON-safe values. Known credential-like keys (including `token`, `password`, `secret`, cookies, session values, API keys, and private keys) are rejected recursively. This is a bounded guard, not a confidentiality or exhaustive secret-detection guarantee; games remain responsible for publishing only non-sensitive diagnostic data.
- Calls are safe to leave in game code because disabled features no-op.
- Do not expose private player data through test state or event payloads.
- Game-specific knowledge belongs in game docs or skills, not in `gdpw`.

Example diagnostic release configuration:

```gdscript
var policy := PlaywrightServiceModule.PlaywrightPayloadPolicy.new(
PackedStringArray(["start_button"]),
PackedStringArray(["unit_"]),
{"route_loaded": PackedStringArray(["route"])},
{"fixture": PackedStringArray(["route", "ready"])}
)
PlaywrightService.configure(
PlaywrightServiceModule.PlaywrightConfig.new(true, true, false, 100, 50, policy)
)
```

## Repository Layout

- `gd/addon/`: Godot plugin source packaged for GDAM and manual installation.
Expand All @@ -294,11 +310,12 @@ Run locally with:

```sh
mise exec -- ./gd/tests/test.sh
mise exec -- bash gd/tests/web_export_test.sh dist/@aviorstudio_gd-playwright.zip
cd cli && mise exec -- go test ./...
cd js && mise exec -- bun test
```

**Correction ([fieldsofrevik#148](https://github.com/aviorstudio/fieldsofrevik/issues/148)):** this README previously said CI ran all three suites, while the common action omitted `js/index.test.js` and the GD release bypassed the common Godot gate. CI and both release targets now run Go, Godot 4.7.2, and JavaScript tests. The GD path additionally tests the exact closed-manifest ZIP through clean editor enable, restart, disable, restart, smoke, and ownership-cleanup checks before transporting those same bytes to publication.
**Correction ([fieldsofrevik#148](https://github.com/aviorstudio/fieldsofrevik/issues/148)):** this README previously said CI ran all three suites, while the common action omitted `js/index.test.js` and the GD release bypassed the common Godot gate. CI and both release targets now run Go, Godot 4.7.2, and JavaScript tests. The GD path additionally tests the exact closed-manifest ZIP through clean editor enable, restart, disable, restart, smoke, ownership-cleanup, and ordinary/diagnostic release-export browser checks before transporting those same bytes to publication.

## License

Expand Down
Binary file added docs/evidence/issue-148/diagnostic-release.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/evidence/issue-148/ordinary-release.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 6 additions & 1 deletion gd/addon/src/element_map_service.gd
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ func setup(owner: Node) -> void:
func register(key: String, center: Vector2, size: Vector2, visible: bool) -> void:
if key.is_empty():
return
if _owner != null and _owner.has_method("_allows_element_key") and not bool(_owner.call("_allows_element_key", key)):
return
var entry := ElementEntry.new(
key,
int(center.x),
Expand Down Expand Up @@ -144,7 +146,10 @@ func flush_to_browser() -> void:
};
window.dispatchEvent(new CustomEvent('godot-elements-updated', { detail: __payload }));
""" % json_string
JavaScriptBridge.eval(js_code)
if _owner != null and _owner.has_method("_browser_eval"):
_owner.call("_browser_eval", js_code)
else:
JavaScriptBridge.eval(js_code)

## Clears all registered elements.
func clear() -> void:
Expand Down
Loading
Loading