Commit Graph

227 Commits

Author SHA1 Message Date
Kevin Veen-Birkenbach
a42930a699 build(make): run e2e without act, lint yaml, js and shell
test-e2e drove Cypress through act, which fails to start where it cannot
resolve a host address for its artifact server. It now starts Flask and
Cypress in one shell via scripts/run-e2e.sh, so both share a network
namespace; the act path stays available as test-e2e-act.

The script guards the cases that made the old target lie: it aborts when
something already serves the port instead of testing that server, checks
that its own Flask is alive before trusting a response, pins Cypress to
the same origin Flask binds, and drops ELECTRON_RUN_AS_NODE, which VS Code
exports and which makes Cypress' bundled Electron reject its own flags.

30 YAML and 18 JavaScript files had no linter. yamllint runs correctness
rules only, because the repository predates it and its cosmetic findings
would be noise; key-duplicates is the one that earns its keep, since
PyYAML keeps the last of two identical keys without complaining. eslint
runs the recommended set and already found a dead getBoundingClientRect()
call in navigation.js. Both get a CI job so make lint and the workflows
stop diverging.

flask>=3.1 because app.config["TRUSTED_HOSTS"] arrived in 3.1 and an older
Flask accepts the key and ignores it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 01:18:27 +02:00
Kevin Veen-Birkenbach
03b7cef90e Release version 2.0.0 2026-05-18 12:26:26 +02:00
Kevin Veen-Birkenbach
4b29448b33 lint 2026-05-18 12:21:05 +02:00
Kevin Veen-Birkenbach
3f30621630 feat(assets): probe-first resolver + SPOT for IMAGE_NAME/PORT + README screenshot
Probe-first asset resolution (regression fix)
---------------------------------------------

cache_manager.cache_file() returned either a relative cache path
(success) or None (failure). The previous app.py fallback
asset['cache'] = cached or asset['source'] mixed both types into
one field, which the template wrapped in url_for('static', ...)
regardless — producing broken
/static/https://file.infinito.nexus/.../logo.png URLs whenever the
source couldn't be downloaded.

- New app/utils/asset_resolver.py: HEAD-probes the URL (3 s
  timeout, image/* content type). On hit, embed directly via a
  new external_url field — no download required. On miss, fall
  back to cache_manager.cache_file. If that also fails, expose
  the source URL via external_url so the browser shows the alt
  text instead of an empty src.
- app.py exposes an asset_src(asset) context processor that
  picks external_url first, then url_for('static', cache),
  so the template never wraps an absolute URL in a static prefix.
- Templates (base, navigation, card) switch to asset_src(...) and
  gate the card image branch on cache or external_url.
- 16 unit tests cover every probe/cache/fallback branch; one live
  integration test exercises the canonical
  https://file.infinito.nexus/assets/img/logo.png to prove the
  probe-first path works end-to-end (cache dir stays empty).
- config.sample.yaml: new Infinito.Nexus card driven by the same
  canonical asset URL.

Single source of truth for IMAGE_NAME and PORT
----------------------------------------------

- env.example is now the only place the literal values live.
- Makefile and docker-compose.yml reference \$(IMAGE_NAME) /
  \${IMAGE_NAME:?…} (same for PORT); no defaults, no silent
  fallbacks.
- New make env / make config bootstrap .env / app/config.yaml
  from their checked-in templates. Idempotent.
- All container-using targets depend on the two bootstrap targets
  so a fresh checkout runs in a single invocation.
- Recipes source .env at recipe-execution time so they pick up a
  freshly bootstrapped .env in the same make invocation.

README
------

- Screenshot added under the title.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 12:19:15 +02:00
Kevin Veen-Birkenbach
39a41e561c Release version 1.2.0 2026-05-11 02:51:17 +02:00
Kevin Veen-Birkenbach
4424db22cb fix(cypress): allow scrollTo on non-scrollable pages in footer dropup test
cy.scrollTo('bottom') threw on CI ("element is not scrollable") whenever
the rendered page fit inside the viewport. Pass ensureScrollable:false
so the call is a no-op on short pages — the footer is already in view
and the subsequent rect-position pre-check enforces the actual
precondition that chooseDirection() needs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 02:38:06 +02:00
Kevin Veen-Birkenbach
28a796e24f chore(claude): enable sandbox and consolidate bash allowlist
Activate the harness sandbox (enabled + autoAllowBashIfSandboxed +
filesystem write/deny rules) and replace the ~30 specific Bash(...)
permission entries with a single Bash(*) wildcard. The existing deny
list (git push --force, git reset --hard, rm -rf, sudo) and ask list
(git push, docker run, curl) keep their precedence.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 02:36:28 +02:00
Kevin Veen-Birkenbach
f3c15e3e1c fix(navigation): unclip dropdowns and flip toward the side with more space
- Move <header> overflow:hidden into body.fullscreen scope and drop the
  implicit-vertical-clip overflow-x:auto from .navbar-nav so dropdown
  menus can escape the navbar.
- Drive top-level dropdowns through bootstrap.Dropdown (popperConfig
  strategy:'fixed'), and add a chooseDirection() helper that toggles
  .dropup/.dropdown on the .nav-item based on space above vs below
  before each show. Split the navigation.css rules to position the menu
  with top:100% or bottom:100% accordingly.
- Mark the dropdown toggle with data-bs-toggle="dropdown" in the
  template; cover that with a Jinja-rendered unit test and add Cypress
  specs for the header (opens downward) and footer (flips to .dropup)
  cases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 02:26:02 +02:00
Kevin Veen-Birkenbach
3301f8d95f chore(claude): allow jobs bash command in harness
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 02:22:06 +02:00
Kevin Veen-Birkenbach
a575fddaa2 build(compose): run npm install in container, persist deps in named volumes
Replace the host-side `make npm-install` step with a compose-level
`command:` override that runs `npm install` inside the container on
every start. Back node_modules and static/vendor with named volumes so
the bind-mounted source tree no longer shadows the install while state
still survives container restarts. Drop the now-redundant npm-install
target and its references in up/dev/prod/test-e2e.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 02:17:53 +02:00
Kevin Veen-Birkenbach
c9fe7d8583 chore(claude): expand harness allowlist and ignore local state
Add permissions for read-only test/inspection commands (make test-e2e,
docker exec/restart, /tmp reads) and gitignore everything under .claude
except the shared settings/gitignore.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 02:15:04 +02:00
Kevin Veen-Birkenbach
03f17a6e05 build(make): run npm-install before docker-compose targets
Add npm-install dependency to up/dev/prod targets so app/static/vendor
and app/node_modules exist on the host before the ./app:/app bind mount
masks the build-time artifacts inside the container.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 00:40:19 +02:00
Kevin Veen-Birkenbach
3132aab2a5 Release version 1.1.0
Some checks failed
CI / Run security workflow (push) Has been cancelled
CI / Run test workflow (push) Has been cancelled
CI / Run lint workflow (push) Has been cancelled
CI / Publish image (push) Has been cancelled
v1.1.0
2026-03-30 10:47:32 +02:00
Kevin Veen-Birkenbach
3d1db1f8ba Updated mirrors
Some checks failed
CI / Run security workflow (push) Has been cancelled
CI / Run test workflow (push) Has been cancelled
CI / Run lint workflow (push) Has been cancelled
CI / Publish image (push) Has been cancelled
2026-03-30 10:46:39 +02:00
Kevin Veen-Birkenbach
58872ced81 fix(ci): grant security-events: write to lint job
The lint-docker job in lint.yml requires security-events: write
for SARIF upload; must be explicitly granted to the caller job.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 10:18:14 +02:00
Kevin Veen-Birkenbach
13b3af3330 Entered and removed whitespaces in README.md 2026-03-30 10:16:53 +02:00
Kevin Veen-Birkenbach
eca7084f4e fix(ci): grant security-events and packages permissions to security job
Reusable workflow calls inherit only explicitly granted permissions.
The nested security job requires packages: read and security-events: write
for CodeQL analysis.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 10:16:30 +02:00
Kevin Veen-Birkenbach
6861b2c0eb fix(nav): prevent navbar items from wrapping to second line
- Set flex-wrap: nowrap on navbar-nav to keep all items in one row
- Add hidden overflow-x scroll (no visible scrollbar) as fallback
- Fix #navbar_logo taking up space when invisible via max-width transition

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 10:10:55 +02:00
Kevin Veen-Birkenbach
66b1f0d029 feat(agents): add AGENTS.md and CLAUDE.md with pre-commit rules
- Add AGENTS.md: require make test before every non-doc commit and
  document the npm vendor asset workflow
- Add CLAUDE.md: instruct agents to read AGENTS.md at conversation start
- Add npm-install dependency to test-e2e Makefile target

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 09:59:09 +02:00
Kevin Veen-Birkenbach
a29a0b1862 feat(vendor): replace CDN dependencies with local npm packages
Introduces a vendor build pipeline so all third-party browser assets
(Bootstrap, Bootstrap Icons, Font Awesome, marked, jQuery) are served
from local static files instead of external CDNs.

- Add app/package.json with vendor deps and postinstall/build scripts
- Add app/scripts/copy-vendor.js to copy assets to static/vendor/
- Update base.html.j2 to use url_for('static', ...) for all vendor assets
- Update Dockerfile to install Node.js/npm and run npm install
- Update .gitignore to exclude app/node_modules/ and app/static/vendor/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 09:29:28 +02:00
Kevin Veen-Birkenbach
252b50d2a7 feat: migrate to pyproject.toml, add test suites, split CI workflows
- Replace requirements.txt with pyproject.toml for modern Python packaging
- Add unit, integration, lint and security test suites under tests/
- Add utils/export_runtime_requirements.py and utils/check_hadolint_sarif.py
- Split monolithic CI into reusable lint.yml, security.yml and tests.yml
- Refactor ci.yml to orchestrate reusable workflows; publish on semver tag only
- Modernize Dockerfile: pin python:3.12-slim, install via pyproject.toml
- Expand Makefile with lint, security, test and CI targets
- Add test-e2e via act with portfolio container stop/start around run
- Fix navbar_logo_visibility.spec.js: win.fullscreen() → win.enterFullscreen()
- Set use_reloader=False in app.run() to prevent double-start in CI
- Add app/core.* and build artifacts to .gitignore
- Fix apt-get → sudo apt-get in tests.yml e2e job
- Fix pip install --ignore-installed to handle stale act cache

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 23:03:09 +02:00
Kevin Veen-Birkenbach
2c61da9fc3 chore: remove comments from settings.json
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 23:37:10 +01:00
Kevin Veen-Birkenbach
2d8185b747 chore: add Claude Code project permissions settings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 23:16:29 +01:00
Kevin Veen-Birkenbach
a47a5babce chore: remove unused imports 2026-03-28 19:08:57 +01:00
Kevin Veen-Birkenbach
3f6c90cc3c Release version 1.0.0 2026-02-19 11:18:50 +01:00
Kevin Veen-Birkenbach
69c4f15ce7 Prepare config.yaml from sample in CI before Cypress 2026-02-19 11:14:52 +01:00
Kevin Veen-Birkenbach
56c1b0d0cd Fix Cypress action for repositories without lockfile 2026-02-19 11:13:12 +01:00
Kevin Veen-Birkenbach
91e9caea48 Fix CI node cache path and npm install strategy 2026-02-19 11:11:11 +01:00
Kevin Veen-Birkenbach
feb6af28ef Add CI workflow for tests and conditional image publish 2026-02-19 11:05:26 +01:00
Kevin Veen-Birkenbach
f8c2b4236b Added d-flex to place logo next to brand 2025-07-21 14:24:28 +02:00
Kevin Veen-Birkenbach
dc2626e020 Added test for log 2025-07-21 12:18:07 +02:00
Kevin Veen-Birkenbach
46b0b744ca Added logo to navbar when in fullscreen 2025-07-21 11:39:59 +02:00
Kevin Veen-Birkenbach
5f2e7ef696 Changed pkgmgr commands 2025-07-12 18:54:42 +02:00
Kevin Veen-Birkenbach
152a85bfb8 Merge branch 'main' of github.com:kevinveenbirkenbach/portfolio 2025-07-12 18:53:03 +02:00
Kevin Veen-Birkenbach
fdfe301868 Renamed PortWebUI to PortUI 2025-07-12 18:52:51 +02:00
Kevin Veen-Birkenbach
cbfe1ed8ae Update README.md
Solved another layout bug
2025-07-12 18:27:47 +02:00
Kevin Veen-Birkenbach
9470162236 Solved formatation bug 2025-07-12 18:26:51 +02:00
Kevin Veen-Birkenbach
6a57fa1e00 Optimized README.md 2025-07-12 18:24:49 +02:00
Kevin Veen-Birkenbach
ab67fc0b29 Renamed portfolio to PortWebUI 2025-07-12 18:22:19 +02:00
Kevin Veen-Birkenbach
e18566d801 Solved some bugs 2025-07-09 22:20:58 +02:00
Kevin Veen-Birkenbach
7bc0f32145 Added cypress tests 2025-07-08 17:16:57 +02:00
Kevin Veen-Birkenbach
6ed3e60dd0 Solved 2tap fullscreen hight bug 2025-07-08 14:39:13 +02:00
Kevin Veen-Birkenbach
ab8ea0dbd6 Added iframe observer 2025-07-07 23:40:35 +02:00
Kevin Veen-Birkenbach
b0446dcd29 Added include svgs 2025-07-07 19:14:29 +02:00
Kevin Veen-Birkenbach
55d309b2d7 Changed fade between html iframe animation 2025-07-07 15:37:24 +02:00
Kevin Veen-Birkenbach
d99a8c8452 Added restore functionality to small logo 2025-07-07 15:06:36 +02:00
Kevin Veen-Birkenbach
3f6a195ecb Optimizid hover 2025-07-07 13:37:02 +02:00
Kevin Veen-Birkenbach
430ea4a120 Solved loading bug 2025-07-07 13:19:49 +02:00
Kevin Veen-Birkenbach
cc0fc9b77f Replaced object by svg 2025-07-07 12:46:56 +02:00
Kevin Veen-Birkenbach
9ada9acb3a Implemented SVG handling 2025-07-07 12:40:25 +02:00