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
17 changes: 16 additions & 1 deletion dbuild/templates/appjail-director.yml.j2
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
# appjail-director.yml
{#- expose is a NAT redirect from the host and appjail refuses it without a
virtualnet ("expose requires the following options: virtualnet"). A
director on the host's stack (alias, ip4_inherit) answers on the host's
ports already, so the README's copy leaves them out. The "deploy" render
keeps them: fjord moves the jails onto networks and drops what does not
apply. #}
{%- set ns = namespace(vnet=true) %}
{%- if appjail and appjail.director and appjail.director.options %}
{%- set ns.vnet = false %}
{%- for opt in appjail.director.options %}
{%- if (opt is mapping and "virtualnet" in opt) or (opt is string and opt.startswith("virtualnet")) %}
{%- set ns.vnet = true %}
{%- endif %}
{%- endfor %}
{%- endif %}

options:
{%- if appjail and appjail.director and appjail.director.options %}
Expand All @@ -20,7 +35,7 @@ services:
name: {{ name | replace("-", "_") }}
options:
- container: 'args:--pull'
{%- for p in ports %}
{%- for p in ports if ns.vnet or (render_mode is defined and render_mode == "deploy") %}
{%- if render_mode is defined and render_mode == "deploy" and loop.first %}
- expose: !ENV '${WEB_PORT}:{{ p.target }} proto:{{ p.protocol }}'
{%- elif loop.first %}
Expand Down
43 changes: 43 additions & 0 deletions tests/test_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -815,3 +815,46 @@ def test_unquotes_a_variable_inside_a_value(self):
self.assertIn("DB_HOST: !ENV '${DB_HOST:127.0.0.1}'", body)
self.assertNotIn("'!ENV", body)
self.assertIn("PLAIN: no variable here", body)


class TestHostNetworkDirectorExpose(unittest.TestCase):
"""A director on the host's stack (alias, ip4_inherit) cannot carry
expose: appjail refuses it without a virtualnet. woodpecker's README
director failed `appjail-director up` (2026-10-11). The deploy bundle
keeps them for fjord, which moves the jails onto networks."""

COMPOSE = (
"name: app\n"
"x-daemonless:\n"
' title: "App"\n'
' description: "An app on the host network."\n'
' category: "Development"\n'
' user: "bsd"\n'
" appjail:\n"
" director:\n"
" options:\n"
" - alias:\n"
" - ip4_inherit:\n"
"services:\n"
" app:\n"
" image: ghcr.io/daemonless/app:latest\n"
" ports:\n"
" - 8000:8000\n"
)

def test_readme_has_no_expose_bundle_keeps_it(self):
with tempfile.TemporaryDirectory() as d:
repo = Path(d)
(repo / ".daemonless").mkdir()
(repo / "compose.yaml").write_text(self.COMPOSE)
(repo / "Containerfile.j2").write_text(CONTAINERFILE_J2)
with _chdir(repo):
cfg = dbuild_config.load(repo)
outputs, errors = docs.render_generated(cfg, argparse.Namespace(community=None), repo)
docs.generate_appjail_files(cfg, repo / "bundle")
bundle = (repo / "bundle" / "appjail-director.yml").read_text()
self.assertEqual(errors, [])
aj = outputs["README.md"].split("### AppJail Director", 1)[1]
self.assertIn("ip4_inherit", aj)
self.assertNotIn("expose:", aj, "no expose next to ip4_inherit")
self.assertIn("expose:", bundle, "the deploy bundle keeps them for fjord")
Loading