From 6016d0916c4f470326de0724f9579c2bd517507a Mon Sep 17 00:00:00 2001 From: Dillard Blom Date: Sat, 26 Sep 2026 16:55:55 +0200 Subject: [PATCH] Fix second Codex finding: packaging symlink produced a dangling-symlink-only archive The ensure-app-name-symlink fix from the previous commit created ../extended_occweb as a symlink so the inherited "../$(app_name)" tar references would resolve regardless of the checkout's real directory name - but the tar invocations ran without --dereference, so GNU tar stored the symlink itself rather than following it into the real files. make source/appstore therefore produced a 1-entry archive containing nothing but a dangling absolute symlink, unusable on any other machine. Caught by a second independent Codex pass; my own "make appstore" test after the first fix only checked the archive's top-level entry name, not its actual file count, so this went unnoticed. Rather than patch this with --dereference, replaced the whole symlink+raw-tar approach with `git archive --prefix=$(app_name)/ HEAD`: it sets the correct top-level folder name directly (no symlink needed at all), and - caught during this fix's own verification, not by either Codex pass - it also closes a separate real leak the symlink approach had: tarring the checkout directory directly included every untracked/gitignored file too (e.g. notes/deploy-nc01.md, which exists specifically because it must never leave this machine). `git archive` only ever includes tracked files. Dev/CI-only files (tests/, Makefile, composer.*, phpunit*.xml, .travis.yml) are now stripped via `export-ignore` entries in a new .gitattributes instead of a long list of tar --exclude flags repeated per target - also means source and appstore now produce identical output, which is fine given neither is part of our actual release flow yet. Verified end to end this time: extracted the resulting archive and confirmed file count, absence of symlinks, absence of tests/notes/ dev files, and correct info.xml content - not just the archive's top-level listing. --- .gitattributes | 11 +++++++++ Makefile | 62 +++++++++++++------------------------------------- 2 files changed, 27 insertions(+), 46 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ca66805 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +# Files excluded from `git archive` output - used by `make appstore` (and by +# our own nc01 deploy tarballs) to strip dev/CI-only files that don't belong +# in a running install, without needing them repeated as tar --exclude flags. +tests export-ignore +.travis.yml export-ignore +phpunit.xml export-ignore +phpunit.integration.xml export-ignore +composer.json export-ignore +composer.lock export-ignore +Makefile export-ignore +.gitattributes export-ignore diff --git a/Makefile b/Makefile index 65a5e02..e922f0c 100644 --- a/Makefile +++ b/Makefile @@ -110,60 +110,30 @@ dist: make source make appstore -# The source/appstore targets below reference ../$(app_name) throughout, -# inherited from the standard Nextcloud app Makefile template, which -# assumes CURDIR's own basename equals the app id. That's not true here -# (this checkout is "occweb", the app id is "extended_occweb"), so make -# ../$(app_name) resolve to this checkout regardless of what it's actually -# named, rather than rewriting every exclude pattern below. -.PHONY: ensure-app-name-symlink -ensure-app-name-symlink: - @if [ "$(notdir $(CURDIR))" != "$(app_name)" ]; then \ - ln -sfn $(CURDIR) $(CURDIR)/../$(app_name); \ - fi - -# Builds the source package +# Both targets package via `git archive` rather than tarring the checkout +# directory directly: it only ever includes tracked files (so untracked/ +# gitignored content - build/, notes/, any stray .env - can never leak into +# a release archive), it sets the correct top-level folder name via +# --prefix regardless of what this checkout is actually called (this repo +# is "occweb", the app id is "extended_occweb" - no symlink trick needed), +# and dev/CI-only files (tests/, Makefile, composer.*, phpunit*.xml, +# .travis.yml) are stripped via the `export-ignore` entries in +# .gitattributes instead of a long, easy-to-miss list of tar --exclude +# flags repeated per target. That also means source and appstore now +# produce the same archive; both targets are kept for compatibility with +# anything that invokes one of them by name. .PHONY: source -source: ensure-app-name-symlink +source: rm -rf $(source_build_directory) mkdir -p $(source_build_directory) - tar \ - --exclude-vcs \ - --exclude="../$(app_name)/build" \ - --exclude="../$(app_name)/js/node_modules" \ - --exclude="../$(app_name)/node_modules" \ - --exclude="../$(app_name)/*.log" \ - --exclude="../$(app_name)/js/*.log" \ - -cvzf $(source_package_name).tar.gz ../$(app_name) + git archive --format=tar --prefix=$(app_name)/ HEAD | gzip > $(source_package_name).tar.gz # Builds the source package for the app store, ignores php and js tests .PHONY: appstore -appstore: ensure-app-name-symlink +appstore: rm -rf $(appstore_build_directory) mkdir -p $(appstore_build_directory) - tar \ - --exclude-vcs \ - --exclude="../$(app_name)/build" \ - --exclude="../$(app_name)/tests" \ - --exclude="../$(app_name)/Makefile" \ - --exclude="../$(app_name)/*.log" \ - --exclude="../$(app_name)/phpunit*xml" \ - --exclude="../$(app_name)/composer.*" \ - --exclude="../$(app_name)/js/node_modules" \ - --exclude="../$(app_name)/js/tests" \ - --exclude="../$(app_name)/js/test" \ - --exclude="../$(app_name)/js/*.log" \ - --exclude="../$(app_name)/js/package.json" \ - --exclude="../$(app_name)/js/bower.json" \ - --exclude="../$(app_name)/js/karma.*" \ - --exclude="../$(app_name)/js/protractor.*" \ - --exclude="../$(app_name)/package.json" \ - --exclude="../$(app_name)/bower.json" \ - --exclude="../$(app_name)/karma.*" \ - --exclude="../$(app_name)/protractor\.*" \ - --exclude="../$(app_name)/.*" \ - --exclude="../$(app_name)/js/.*" \ - -cvzf $(appstore_package_name).tar.gz ../$(app_name) + git archive --format=tar --prefix=$(app_name)/ HEAD | gzip > $(appstore_package_name).tar.gz .PHONY: test test: composer