Skip to content

feat: nginx cache optimizations, TLS key permissions, and test framework migration - #142

Draft
florentianayuwono wants to merge 11 commits into
mainfrom
feat/optimizations-and-refactorings
Draft

feat: nginx cache optimizations, TLS key permissions, and test framework migration#142
florentianayuwono wants to merge 11 commits into
mainfrom
feat/optimizations-and-refactorings

Conversation

@florentianayuwono

Copy link
Copy Markdown
Contributor

Overview

This PR implements several nginx cache optimizations, a TLS security hardening, and migrates both unit and integration tests to modern frameworks.

Stories

Story 1 & 2: Configurable cache-inactive and cache-max-size

  • Added cache-inactive config option (default: 10m) to content-cache-backends-config
  • Added cache-max-size config option (default: empty = no limit) to content-cache-backends-config
  • Both values flow through the relation databag into nginx's proxy_cache_path directive
  • Allows operators to tune LRU eviction behaviour and prevent filesystem exhaustion

Story 3: Always-on proxy_cache_lock

  • Added proxy_cache_lock on to all nginx location blocks
  • Prevents thundering herd on cache miss: only one upstream fetch per cache miss

Story 4: TLS private key permission hardening

  • Changed os.chmod(pem_file_path, 0o644)0o640
  • Restricts TLS private key read access to www-data user/group only

Story 5: Test framework migration

  • Unit tests: migrated content-cache and content-cache-backends-config from ops.testing.Harness to ops-scenario (state-based testing)
  • Integration tests: migrated from async python-libjuju + pytest-asyncio to sync jubilant

Commits

  • feat(backends-config): add cache-inactive and cache-max-size config options
  • feat(content-cache): wire cache-inactive and cache-max-size to proxy_cache_path
  • feat(nginx): add proxy_cache_lock on to all location blocks
  • fix(tls): restrict TLS private key file permissions to 0o640
  • refactor(unit): migrate content-cache unit tests to ops-scenario
  • refactor(unit): migrate backends-config unit tests to ops-scenario
  • refactor(integration): migrate content-cache integration tests to jubilant

@florentianayuwono
florentianayuwono requested a review from a team as a code owner August 8, 2026 14:10
@florentianayuwono
florentianayuwono requested review from swetha1654 and yanksyoon and removed request for a team August 8, 2026 14:10
@florentianayuwono
florentianayuwono marked this pull request as draft August 8, 2026 14:10
@florentianayuwono florentianayuwono self-assigned this Aug 8, 2026
@florentianayuwono
florentianayuwono force-pushed the feat/optimizations-and-refactorings branch 3 times, most recently from fc56f29 to d8e598b Compare August 8, 2026 16:34
@florentianayuwono
florentianayuwono force-pushed the feat/optimizations-and-refactorings branch from d8e598b to d9a9b4d Compare August 8, 2026 18:23
Base automatically changed from feat/support-https-isd-6137 to main August 18, 2026 14:24
florentianayuwono and others added 8 commits August 19, 2026 01:21
…ptions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…cache_path

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Rewrote test_charm.py using scenario.Context, scenario.State,
  and scenario.SubordinateRelation (required for subordinate charm)
- Rewrote conftest.py with scenario fixtures (ctx, ctx_leader)
- Added ops-scenario>=7.0.0,<9.0.0 to requirements.txt
- Fixed try-except-raise pattern in state.py validators to satisfy
  both DCO051 (flake8) and W0706 (pylint)
- All 57 unit tests pass; lint 10.00/10

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ilant

- Replace async/await + python-libjuju/pytest-asyncio with sync jubilant
- Rewrite conftest.py: juju fixture using jubilant.temp_model(),
  all fixtures sync, app fixtures return str names instead of Application
- Rewrite helpers.py: CacheTester uses jubilant.Juju + app name strings,
  read_file/get_cache_backends/run_in_unit use juju.exec()
- Rewrite test_basic.py, test_healthchecks.py, test_metric.py,
  test_tls_cert.py: remove async def / await / asyncio.sleep,
  use juju.wait() predicates, juju.integrate(), juju.remove_relation()
- Update tox.ini: replace juju+pytest-asyncio with jubilant>=1.10.0,<2.0.0
- Use correct jubilant API: juju.status() (method), app_status.current,
  workload_status.current/.message, add_unit(app, num_units=1)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When ssl_verify=false, nginx should not verify the backend's TLS
certificate — neither in healthchecks nor in proxied requests.
Previously, proxy_ssl_verify was always set to 'on' whenever a CA
bundle existed, regardless of the ssl_verify config value. This caused
test_healthchecks_ssl_verify[no_ssl_verify] to fail with 502 because
the backend's self-signed cert (not signed by cert_app's CA) could not
be verified.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add juju.wait(active) after integrate_config()+setup_config() in
test_tls_termination_full_lifecycle. Without this wait, the TLS cert
from cache-lego can arrive before config subordinate hooks deliver valid
backend data, leaving the charm blocked on 'Waiting for integration with
config charm' for the entire 10-min window.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@florentianayuwono
florentianayuwono force-pushed the feat/optimizations-and-refactorings branch from 9a84a36 to e0ad1d3 Compare August 18, 2026 19:04
- test_charm.py: use get_cache_backend_url (singular) and cache-backend
  key (singular plain string) from PR #141; fix mock targets to match
  current function names (write_ca_bundle, write_certificate)
- test_charm.py: patch _get_cache_cert_path in Harness TLS test so
  _load_nginx_config proceeds past the cert-file guard
- test_nginx_manager.py: keep monkeypatch approach for ca_certs and add
  ssl_verify condition from c2b7ab4 (no proxy_ssl when ssl_verify=false)
- helpers.py: get_cache_backends reads cache-backend (singular) key and
  wraps the plain URL string in a list for backward-compatible callers

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@florentianayuwono
florentianayuwono force-pushed the feat/optimizations-and-refactorings branch from e0ad1d3 to cd92b4e Compare August 18, 2026 19:14
jubilant.deploy(num_units=0) passes --num-units 0 to the Juju CLI which
rejects it with 'must be a positive integer'. The original asyncio
python-libjuju model.deploy() accepted 0.

Remove num_units from the three headless/subordinate deploy calls so
jubilant does not add --num-units at all, letting Juju use the default
behaviour for each charm type.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jubilant.all_active without arguments checks ALL model apps including
subordinate charms (config-alt, metric) that have no units until
integrated. These apps always show 'unknown' status and cause
juju.wait(all_active) to time out.

Replace each bare all_active call with a lambda scoped to only the apps
relevant to that test: cache app + currently-integrated config/metric apps.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant