Skip to content

Commit

Permalink
Fail if platform packages are part of app source
Browse files Browse the repository at this point in the history
Sometimes, users download a slug from Heroku, and put that slug into a Git repo.

As a result, the source will contain hundreds of megabytes of binaries in .heroku/php/, and platform installation will fail because Composer things nothing needs to be installed (which is correct, but the post-install hooks that set up $PATH etc will not trigger).

Better UX to fail the build in this case.

Also gives a human-readable error now in case the buildpack is set twice on the app for some reason.

GUS-W-12004810
  • Loading branch information
dzuelke committed Nov 3, 2022
1 parent fc88519 commit 9c96009
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
- ext-newrelic/10.3.0.315 [David Zuelke]
- ext-phalcon/5.1.0 [David Zuelke]

### CHG

- Fail if platform packages dir is part of app source [David Zuelke]

## v226 (2022-10-27)

### ADD
Expand Down
44 changes: 42 additions & 2 deletions bin/compile
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,48 @@ fi

# PHP expects to be installed in /app/.heroku/php because of compiled paths, let's set that up!
mkdir -p /app/.heroku
# all system packages live in there
mkdir -p $build_dir/.heroku/php
# other buildpacks use this magic directory, too
mkdir -p $build_dir/.heroku
# all our system packages live in there
mkdir $build_dir/.heroku/php || {
# looks like platform packages are already there
# this can happen if the buildpack is set twice, or if a user is trying to build an already built app
# (e.g. by downloading a slug from Heroku and checking it into Git)
mcount "failures.platform.slug_as_source"
error <<-EOF
Your app source code contains artifacts from a previous build!
A '.heroku/php/' directory exists in your app source, but this
directory is created during a build of your app and should not
be in your source repository, as it contains binaries for PHP,
web servers, PHP extensions, and so forth.
This situation can happen if you:
1) have accidentally set this buildpack on your app twice;
2) downloaded a built app ("slug") and used it as source code.
To address situation 1, check the 'heroku buildpacks' command.
To address situation 2, ensure the following directories are
not part of your source code in your version control system:
- .heroku/
- .profile.d/
- vendor/
It is recommended you create a new Git repository that doesn't
have these directories in its commit history. If you only
perform a 'git rm', the binaries will remain part of your code
repository, and inflate its size by hundreds of megabytes. You
may also use common techniques for rewriting commit history to
retroactively remove the directories from the old commits that
introduced them.
If you were using other buildpacks together with PHP, you may
want to ensure that those buildpacks' build artifacts, such as
a Node.js 'node_modules/' directory, are also not part of your
source code repository.
EOF
}
# set up Composer
export COMPOSER_HOME=$cache_dir/.composer
mkdir -p $COMPOSER_HOME
Expand Down
31 changes: 31 additions & 0 deletions test/spec/bugs_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,35 @@
end
end
end
context "that is built twice" do
# sometimes, customers download a slug for an existing app and check that into a new repo
# that means the source includes the binaries in .heroku/php/, which blows up the size by 100s of MB
# it also causes the platform install to fail because Composer sees everything is there and no post-install hooks to set up $PATH etc will be run
context "because of a slug getting used as the app source" do
it "fails the build" do
app = new_app_with_stack_and_platrepo("test/fixtures/default", allow_failure: true).tap do |app|
app.before_deploy(:append) do
FileUtils.mkdir_p(".heroku/php")
FileUtils.touch(".heroku/php/composer.lock")
end
end
app.deploy do |app|
expect(app.output).to match("Your app source code contains artifacts from a previous build")
end
end
end
# it can also happen if the PHP buildpack runs twice during a build
context "because the buildpack ran twice" do
it "fails the build" do
buildpacks = [
"heroku/php",
:default
]
app = new_app_with_stack_and_platrepo("test/fixtures/default", buildpacks: buildpacks, allow_failure: true)
app.deploy do |app|
expect(app.output).to match("Your app source code contains artifacts from a previous build")
end
end
end
end
end

0 comments on commit 9c96009

Please sign in to comment.