├── .github ├── .syncignore ├── CODEOWNERS ├── dependabot.yml ├── workflows │ ├── synchronize-labels.yml │ ├── lint.yml │ ├── lint-yaml.yml │ ├── label-pr.yml │ ├── publish-releases.yml │ ├── test-pull-request.yml │ ├── update-github-config.yml │ ├── approve-bot-pr.yml │ ├── update-buildpack-toml.yml │ ├── update-go-mod-version.yml │ ├── create-draft-release.yml │ └── push-buildpackage.yml ├── .patch_files └── labels.yml ├── .gitignore ├── integration ├── testdata │ ├── pipenv │ │ ├── .gitignore │ │ ├── Procfile │ │ ├── Pipfile │ │ └── server.py │ ├── conda │ │ ├── Procfile │ │ ├── environment.yml │ │ └── app.py │ ├── ca_cert_apps │ │ ├── bindings │ │ │ ├── type │ │ │ └── ca.pem │ │ ├── pipenv │ │ │ ├── .gitignore │ │ │ ├── Procfile │ │ │ ├── Pipfile │ │ │ ├── server.py │ │ │ ├── cert.pem │ │ │ └── key.pem │ │ ├── conda │ │ │ ├── Procfile │ │ │ ├── environment.yml │ │ │ ├── app.py │ │ │ ├── cert.pem │ │ │ └── key.pem │ │ ├── pip │ │ │ ├── Procfile │ │ │ ├── requirements.txt │ │ │ ├── server.py │ │ │ ├── cert.pem │ │ │ └── key.pem │ │ ├── no_package_manager │ │ │ ├── Procfile │ │ │ ├── app.py │ │ │ ├── cert.pem │ │ │ └── key.pem │ │ └── client_certs │ │ │ ├── ca.pem │ │ │ ├── cert.pem │ │ │ └── key.pem │ ├── pip │ │ ├── Procfile │ │ ├── requirements.txt │ │ └── server.py │ ├── poetry-dep-only │ │ ├── Procfile │ │ ├── server.py │ │ ├── pyproject.toml │ │ └── poetry.lock │ ├── no_package_manager │ │ └── hello.py │ └── poetry-run │ │ ├── default_app │ │ └── server.py │ │ ├── pyproject.toml │ │ └── poetry.lock ├── init_test.go ├── poetry_run_test.go ├── poetry_dep_only_test.go ├── conda_test.go ├── pip_test.go ├── pipenv_test.go └── no_package_manager_test.go ├── rfcs └── 0001-restructure.md ├── scripts ├── .util │ ├── tools.json │ ├── builders.sh │ ├── print.sh │ └── tools.sh ├── publish.sh ├── integration.sh └── package.sh ├── integration.json ├── NOTICE ├── package.toml ├── README.md ├── go.mod ├── LICENSE └── go.sum /.github/.syncignore: -------------------------------------------------------------------------------- 1 | CODEOWNERS 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bin 2 | /build 3 | .idea/ -------------------------------------------------------------------------------- /integration/testdata/pipenv/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | venv -------------------------------------------------------------------------------- /integration/testdata/conda/Procfile: -------------------------------------------------------------------------------- 1 | web: python app.py 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @paketo-buildpacks/python-maintainers 2 | -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/bindings/type: -------------------------------------------------------------------------------- 1 | ca-certificates -------------------------------------------------------------------------------- /integration/testdata/pip/Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn server:app 2 | -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/pipenv/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | venv -------------------------------------------------------------------------------- /integration/testdata/pipenv/Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn server:app 2 | -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/conda/Procfile: -------------------------------------------------------------------------------- 1 | web: python app.py 2 | -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/pip/Procfile: -------------------------------------------------------------------------------- 1 | web: python server.py 2 | -------------------------------------------------------------------------------- /integration/testdata/poetry-dep-only/Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn server:app 2 | -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/no_package_manager/Procfile: -------------------------------------------------------------------------------- 1 | web: python app.py 2 | -------------------------------------------------------------------------------- /integration/testdata/conda/environment.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - python=3.9 3 | - flask=2.0.2 4 | - Werkzeug==2.2.2 -------------------------------------------------------------------------------- /integration/testdata/no_package_manager/hello.py: -------------------------------------------------------------------------------- 1 | i = 0 2 | while i < 10: 3 | print("Hello") 4 | i +=1 5 | -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/pipenv/Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn --certfile=cert.pem --keyfile=key.pem server:app 2 | -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/conda/environment.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - python=3.9 3 | - flask=2.0.2 4 | - Werkzeug==2.2.2 -------------------------------------------------------------------------------- /rfcs/0001-restructure.md: -------------------------------------------------------------------------------- 1 | This page has moved. The new location is: 2 | https://github.com/paketo-buildpacks/rfcs/blob/main/text/python/0001-restructure.md 3 | -------------------------------------------------------------------------------- /integration/testdata/pip/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.1.3 2 | Jinja2==3.1.2 3 | MarkupSafe==2.1.1 4 | Werkzeug==2.2.1 5 | gunicorn==20.1.0 6 | itsdangerous==2.1.2 7 | -------------------------------------------------------------------------------- /scripts/.util/tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "createpackage": "v1.73.0", 3 | "jam": "v2.15.1", 4 | "libpaktools": "v0.3.0", 5 | "pack": "v0.39.1", 6 | "yj": "v5.1.0" 7 | } 8 | -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/pip/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.1.3 2 | Jinja2==3.1.2 3 | MarkupSafe==2.1.1 4 | Werkzeug==2.2.1 5 | gunicorn==20.1.0 6 | itsdangerous==2.1.2 7 | -------------------------------------------------------------------------------- /integration.json: -------------------------------------------------------------------------------- 1 | { 2 | "builders": [ 3 | "index.docker.io/paketobuildpacks/builder-jammy-buildpackless-base:latest", 4 | "index.docker.io/paketobuildpacks/ubuntu-noble-builder-buildpackless:latest" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /integration/testdata/pipenv/Pipfile: -------------------------------------------------------------------------------- 1 | [packages] 2 | Flask = "==2.1.3" 3 | gunicorn = "*" 4 | itsdangerous = "==2.1.2" 5 | 6 | [dev-packages] 7 | tox = "*" 8 | coverage = "*" 9 | "flake8" = "*" 10 | flask-testing = "*" 11 | -------------------------------------------------------------------------------- /integration/testdata/pip/server.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | app = Flask(__name__) 3 | 4 | @app.route('/') 5 | def hello_world(): 6 | return 'Hello, World with pip!' 7 | 8 | if __name__ == "__main__": 9 | app.run() 10 | -------------------------------------------------------------------------------- /integration/testdata/poetry-dep-only/server.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | app = Flask(__name__) 3 | 4 | @app.route('/') 5 | def hello_world(): 6 | return 'Hello, World!' 7 | 8 | if __name__ == "__main__": 9 | app.run() 10 | -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/pipenv/Pipfile: -------------------------------------------------------------------------------- 1 | [packages] 2 | Flask = "==2.1.3" 3 | gunicorn = "*" 4 | itsdangerous = "==2.1.2" 5 | 6 | [dev-packages] 7 | tox = "*" 8 | coverage = "*" 9 | "flake8" = "*" 10 | flask-testing = "*" 11 | -------------------------------------------------------------------------------- /integration/testdata/poetry-run/default_app/server.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from flask import Flask 4 | app = Flask(__name__) 5 | 6 | @app.route('/') 7 | def hello_world(): 8 | return 'Hello, World!' 9 | 10 | if __name__ == "__main__": 11 | app.run() 12 | 13 | def run(): 14 | port = int(os.getenv("PORT")) 15 | app.run(host='0.0.0.0', port=port) 16 | -------------------------------------------------------------------------------- /integration/testdata/poetry-dep-only/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "default_app" 3 | version = "0.1.0" 4 | description = "" 5 | authors = [] 6 | package-mode = false 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.12" 10 | Flask = "^2.0.3" 11 | gunicorn = "^20.1.0" 12 | setuptools = "^69" 13 | 14 | [build-system] 15 | requires = ["poetry-core>=1.0.0"] 16 | build-backend = "poetry.core.masonry.api" 17 | -------------------------------------------------------------------------------- /integration/testdata/poetry-run/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "default_app" 3 | version = "0.1.0" 4 | description = "" 5 | authors = [] 6 | package-mode = false 7 | 8 | [tool.poetry.dependencies] 9 | python = "3.14" 10 | Flask = "^3.1.2" 11 | 12 | [tool.poetry.scripts] 13 | my-script = "default_app.server:run" 14 | 15 | [build-system] 16 | requires = ["poetry-core>=1.0.0"] 17 | build-backend = "poetry.core.masonry.api" 18 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: gomod 5 | directory: "/" 6 | schedule: 7 | interval: daily 8 | allow: 9 | # Allow both direct and indirect updates for all packages 10 | - dependency-type: "all" 11 | # group all minor and patch dependency updates together 12 | groups: 13 | go-modules: 14 | patterns: 15 | - "*" 16 | update-types: 17 | - "minor" 18 | - "patch" 19 | -------------------------------------------------------------------------------- /.github/workflows/synchronize-labels.yml: -------------------------------------------------------------------------------- 1 | name: Synchronize Labels 2 | "on": 3 | push: 4 | branches: 5 | - main 6 | paths: 7 | - .github/labels.yml 8 | workflow_dispatch: {} 9 | jobs: 10 | synchronize: 11 | name: Synchronize Labels 12 | runs-on: 13 | - ubuntu-24.04 14 | steps: 15 | - uses: actions/checkout@v6 16 | - uses: micnncim/action-label-syncer@v1 17 | env: 18 | GITHUB_TOKEN: ${{ github.token }} 19 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | golangci: 10 | name: lint 11 | runs-on: ubuntu-24.04 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v6 15 | 16 | - name: Setup Go 17 | uses: actions/setup-go@v6 18 | with: 19 | go-version-file: go.mod 20 | 21 | - name: golangci-lint 22 | uses: golangci/golangci-lint-action@v9 23 | with: 24 | version: latest 25 | args: --timeout 3m0s 26 | -------------------------------------------------------------------------------- /integration/testdata/conda/app.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from flask import Flask 5 | 6 | app = Flask(__name__) 7 | 8 | 9 | @app.route('/') 10 | def root(): 11 | python_version = sys.version 12 | return "Hello, world!\nUsing python: " + python_version + "\n" 13 | 14 | 15 | if __name__ == '__main__': 16 | # Get port from environment variable or choose 9099 as local default 17 | port = int(os.getenv("PORT", 8080)) 18 | # Run the app, listening on all IPs with our chosen port number 19 | app.run(host='0.0.0.0', port=port, debug=True) 20 | -------------------------------------------------------------------------------- /integration/testdata/pipenv/server.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request 2 | import subprocess 3 | import gunicorn 4 | 5 | 6 | app = Flask(__name__) 7 | 8 | @app.route("/") 9 | def hello(): 10 | return "Hello, World with pipenv!" 11 | 12 | @app.route('/execute', methods=['POST']) 13 | def execute(): 14 | with open('runtime.py', 'w') as f: 15 | f.write(request.values.get('code')) 16 | return subprocess.check_output(["python", "runtime.py"]) 17 | 18 | @app.route('/versions') 19 | def versions(): 20 | version = gunicorn.__version__ 21 | return "Gunicorn version: " + version 22 | 23 | app.debug=True 24 | 25 | print("wow") -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-Present CloudFoundry.org Foundation, Inc. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /.github/.patch_files: -------------------------------------------------------------------------------- 1 | .github/.patch_files 2 | .github/.syncignore 3 | .github/CODEOWNERS 4 | .github/dependabot.yml 5 | .github/labels.yml 6 | .github/workflows/approve-bot-pr.yml 7 | .github/workflows/label-pr.yml 8 | .github/workflows/lint-yaml.yml 9 | .github/workflows/lint.yml 10 | .github/workflows/synchronize-labels.yml 11 | .github/workflows/test-pull-request.yml 12 | .github/workflows/update-buildpack-toml.yml 13 | .github/workflows/update-github-config.yml 14 | .gitignore 15 | LICENSE 16 | NOTICE 17 | README.md 18 | scripts/.util/builders.sh 19 | scripts/.util/print.sh 20 | scripts/.util/tools.json 21 | scripts/.util/tools.sh 22 | scripts/integration.sh 23 | -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/pip/server.py: -------------------------------------------------------------------------------- 1 | import os, sys, ssl 2 | 3 | from flask import Flask 4 | 5 | app = Flask(__name__) 6 | 7 | @app.route('/') 8 | def root(): 9 | python_version = sys.version 10 | return "Powered by Paketo Buildpacks\nUsing python: " + python_version + "\n" 11 | 12 | if __name__ == '__main__': 13 | port = int(os.getenv("PORT", 8080)) 14 | 15 | context = ssl.SSLContext(ssl.PROTOCOL_TLS) 16 | context.verify_mode = ssl.CERT_REQUIRED 17 | context.load_default_certs() 18 | context.load_cert_chain(certfile='cert.pem', keyfile="key.pem") 19 | 20 | app.run(host='0.0.0.0', port=port, debug=True, ssl_context=context) -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/conda/app.py: -------------------------------------------------------------------------------- 1 | import os, sys, ssl 2 | 3 | from flask import Flask 4 | 5 | app = Flask(__name__) 6 | 7 | @app.route('/') 8 | def root(): 9 | python_version = sys.version 10 | return "Powered by Paketo Buildpacks\nUsing python: " + python_version + "\n" 11 | 12 | if __name__ == '__main__': 13 | port = int(os.getenv("PORT", 8080)) 14 | 15 | context = ssl.SSLContext(ssl.PROTOCOL_TLS) 16 | context.verify_mode = ssl.CERT_REQUIRED 17 | context.load_default_certs() 18 | context.load_cert_chain(certfile='cert.pem', keyfile="key.pem") 19 | 20 | app.run(host='0.0.0.0', port=port, debug=True, ssl_context=context) 21 | -------------------------------------------------------------------------------- /.github/workflows/lint-yaml.yml: -------------------------------------------------------------------------------- 1 | name: Lint Workflows 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '.github/**.yml' 7 | - '.github/**.yaml' 8 | 9 | jobs: 10 | lintYaml: 11 | runs-on: ubuntu-24.04 12 | steps: 13 | - uses: actions/checkout@v6 14 | 15 | - name: Checkout github-config 16 | uses: actions/checkout@v6 17 | with: 18 | repository: paketo-buildpacks/github-config 19 | path: github-config 20 | 21 | - name: Set up Python 22 | uses: actions/setup-python@v5 23 | with: 24 | python-version: 3.8 25 | 26 | - name: Install yamllint 27 | run: pip install yamllint 28 | 29 | - name: Lint YAML files 30 | run: yamllint ./.github -c github-config/.github/.yamllint 31 | -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/no_package_manager/app.py: -------------------------------------------------------------------------------- 1 | import http.server, ssl 2 | from http import HTTPStatus 3 | 4 | class Handler(http.server.SimpleHTTPRequestHandler): 5 | def do_GET(self): 6 | self.send_response(HTTPStatus.OK) 7 | self.end_headers() 8 | self.wfile.write(b'Powered by Paketo Buildpacks') 9 | 10 | # SSL 11 | context = ssl.SSLContext(ssl.PROTOCOL_TLS) 12 | context.verify_mode = ssl.CERT_REQUIRED 13 | context.load_default_certs(ssl.Purpose.CLIENT_AUTH) 14 | context.load_cert_chain(certfile='cert.pem', keyfile="key.pem") 15 | # Wrap http 16 | server_address = ('0.0.0.0', 8080) 17 | httpd = http.server.HTTPServer(server_address, Handler) 18 | httpd.socket = context.wrap_socket(httpd.socket, server_side=True) 19 | 20 | httpd.serve_forever() -------------------------------------------------------------------------------- /scripts/.util/builders.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | set -o pipefail 5 | 6 | # shellcheck source=SCRIPTDIR/print.sh 7 | source "$(dirname "${BASH_SOURCE[0]}")/print.sh" 8 | 9 | function util::builders::list() { 10 | local integrationJSON="${1}" 11 | local builders="" 12 | if [[ -f "${integrationJSON}" ]]; then 13 | builders="$(jq --compact-output 'select(.builder != null) | [.builder]' "${integrationJSON}")" 14 | 15 | if [[ -z "${builders}" ]]; then 16 | builders="$(jq --compact-output 'select(.builders != null) | .builders' "${integrationJSON}")" 17 | fi 18 | fi 19 | 20 | if [[ -z "${builders}" ]]; then 21 | util::print::info "No builders specified. Falling back to default builder..." 22 | builders="$(jq --compact-output --null-input '["index.docker.io/paketobuildpacks/builder-jammy-buildpackless-base:latest"]')" 23 | fi 24 | 25 | echo "${builders}" 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/label-pr.yml: -------------------------------------------------------------------------------- 1 | name: Set / Validate PR Labels 2 | on: 3 | pull_request_target: 4 | branches: 5 | - main 6 | types: 7 | - synchronize 8 | - opened 9 | - reopened 10 | - labeled 11 | - unlabeled 12 | 13 | concurrency: pr_labels_${{ github.event.number }} 14 | 15 | jobs: 16 | autolabel: 17 | name: Ensure Minimal Semver Labels 18 | runs-on: ubuntu-24.04 19 | steps: 20 | - name: Check Minimal Semver Labels 21 | uses: mheap/github-action-required-labels@v5 22 | with: 23 | count: 1 24 | labels: semver:major, semver:minor, semver:patch 25 | mode: exactly 26 | env: 27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 28 | 29 | - name: Auto-label Semver 30 | if: ${{ failure() }} 31 | uses: paketo-buildpacks/github-config/actions/pull-request/auto-semver-label@main 32 | env: 33 | GITHUB_TOKEN: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }} 34 | -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/pipenv/server.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request 2 | import subprocess 3 | import gunicorn 4 | import os, ssl 5 | 6 | app = Flask(__name__) 7 | 8 | @app.route("/") 9 | def hello(): 10 | return "Hello, World with pipenv!" 11 | 12 | @app.route('/execute', methods=['POST']) 13 | def execute(): 14 | with open('runtime.py', 'w') as f: 15 | f.write(request.values.get('code')) 16 | return subprocess.check_output(["python", "runtime.py"]) 17 | 18 | @app.route('/versions') 19 | def versions(): 20 | version = gunicorn.__version__ 21 | return "Gunicorn version: " + version 22 | 23 | app.debug=True 24 | 25 | print("wow") 26 | 27 | if __name__ == "__main__": 28 | port = int(os.getenv("PORT", 8080)) 29 | 30 | context = ssl.SSLContext(ssl.PROTOCOL_TLS) 31 | context.verify_mode = ssl.CERT_REQUIRED 32 | context.load_default_certs() 33 | context.load_cert_chain(certfile='cert.pem', keyfile="key.pem") 34 | 35 | app.run(host='0.0.0.0', port=port, debug=True, ssl_context=context) -------------------------------------------------------------------------------- /scripts/.util/print.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | set -o pipefail 5 | 6 | function util::print::title() { 7 | local blue reset message 8 | blue="\033[0;34m" 9 | reset="\033[0;39m" 10 | message="${1}" 11 | 12 | echo -e "\n${blue}${message}${reset}" >&2 13 | } 14 | 15 | function util::print::info() { 16 | local message 17 | message="${1}" 18 | 19 | echo -e "${message}" >&2 20 | } 21 | 22 | function util::print::error() { 23 | local message red reset 24 | message="${1}" 25 | red="\033[0;31m" 26 | reset="\033[0;39m" 27 | 28 | echo -e "${red}${message}${reset}" >&2 29 | exit 1 30 | } 31 | 32 | function util::print::success() { 33 | local message green reset 34 | message="${1}" 35 | green="\033[0;32m" 36 | reset="\033[0;39m" 37 | 38 | echo -e "${green}${message}${reset}" >&2 39 | exitcode="${2:-0}" 40 | exit "${exitcode}" 41 | } 42 | 43 | function util::print::warn() { 44 | local message yellow reset 45 | message="${1}" 46 | yellow="\033[0;33m" 47 | reset="\033[0;39m" 48 | 49 | echo -e "${yellow}${message}${reset}" >&2 50 | exit 0 51 | } 52 | -------------------------------------------------------------------------------- /integration/init_test.go: -------------------------------------------------------------------------------- 1 | package integration_test 2 | 3 | import ( 4 | "os/exec" 5 | "path/filepath" 6 | "testing" 7 | "time" 8 | 9 | "github.com/sclevine/spec" 10 | "github.com/sclevine/spec/report" 11 | 12 | . "github.com/onsi/gomega" 13 | "github.com/onsi/gomega/format" 14 | ) 15 | 16 | var pythonBuildpack string 17 | 18 | func TestIntegration(t *testing.T) { 19 | Expect := NewWithT(t).Expect 20 | 21 | format.MaxLength = 0 22 | 23 | output, err := exec.Command("bash", "-c", "../scripts/package.sh --version 1.2.3").CombinedOutput() 24 | Expect(err).NotTo(HaveOccurred(), string(output)) 25 | 26 | pythonBuildpack, err = filepath.Abs("../build/buildpackage.cnb") 27 | Expect(err).NotTo(HaveOccurred()) 28 | 29 | SetDefaultEventuallyTimeout(10 * time.Second) 30 | 31 | suite := spec.New("Integration", spec.Report(report.Terminal{}), spec.Parallel()) 32 | suite("Conda", testConda) 33 | suite("Pip", testPip) 34 | suite("Pipenv", testPipenv) 35 | suite("PoetryDepOnly", testPoetryDepOnly) 36 | suite("PoetryRun", testPoetryRun) 37 | suite("NoPackageManager", testNoPackageManager) 38 | suite.Run(t) 39 | } 40 | -------------------------------------------------------------------------------- /.github/workflows/publish-releases.yml: -------------------------------------------------------------------------------- 1 | name: Publish Draft Releases 2 | 3 | on: 4 | workflow_dispatch: {} 5 | schedule: 6 | - cron: '0 5 * * FRI' # Weekly on Friday at 5:00 AM UTC 7 | 8 | concurrency: 9 | group: publish-release 10 | 11 | jobs: 12 | publish: 13 | name: Publish 14 | runs-on: ubuntu-24.04 15 | steps: 16 | - name: Publish Draft Release With Highest Semantic Version 17 | id: drafts 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }} 20 | uses: paketo-buildpacks/github-config/actions/release/publish-drafts@main 21 | with: 22 | repo: ${{ github.repository }} 23 | 24 | failure: 25 | name: Alert on Failure 26 | runs-on: ubuntu-24.04 27 | needs: [ publish ] 28 | if: ${{ always() && needs.publish.result == 'failure' }} 29 | steps: 30 | - name: File Failure Alert Issue 31 | uses: paketo-buildpacks/github-config/actions/issue/file@main 32 | with: 33 | token: ${{ secrets.GITHUB_TOKEN }} 34 | repo: ${{ github.repository }} 35 | label: "failure:release" 36 | comment_if_exists: true 37 | issue_title: "Failure: Publish draft releases" 38 | issue_body: | 39 | Publish All Draft Releases workflow [failed](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}). 40 | comment_body: | 41 | Another failure occurred: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} 42 | -------------------------------------------------------------------------------- /package.toml: -------------------------------------------------------------------------------- 1 | 2 | [buildpack] 3 | uri = "build/buildpack.tgz" 4 | 5 | [[dependencies]] 6 | uri = "docker://docker.io/paketobuildpacks/cpython:1.18.4" 7 | 8 | [[dependencies]] 9 | uri = "docker://docker.io/paketobuildpacks/pip:0.24.8" 10 | 11 | [[dependencies]] 12 | uri = "docker://docker.io/paketobuildpacks/pipenv:1.23.9" 13 | 14 | [[dependencies]] 15 | uri = "docker://docker.io/paketobuildpacks/pipenv-install:0.7.7" 16 | 17 | [[dependencies]] 18 | uri = "docker://docker.io/paketobuildpacks/pip-install:0.7.9" 19 | 20 | [[dependencies]] 21 | uri = "docker://docker.io/paketobuildpacks/python-start:0.15.4" 22 | 23 | [[dependencies]] 24 | uri = "docker://docker.io/paketobuildpacks/miniconda:0.11.6" 25 | 26 | [[dependencies]] 27 | uri = "docker://docker.io/paketobuildpacks/conda-env-update:0.8.3" 28 | 29 | [[dependencies]] 30 | uri = "docker://docker.io/paketobuildpacks/poetry:0.14.5" 31 | 32 | [[dependencies]] 33 | uri = "docker://docker.io/paketobuildpacks/poetry-install:0.6.12" 34 | 35 | [[dependencies]] 36 | uri = "docker://docker.io/paketobuildpacks/poetry-run:0.5.8" 37 | 38 | [[dependencies]] 39 | uri = "docker://docker.io/paketobuildpacks/procfile:5.12.0" 40 | 41 | [[dependencies]] 42 | uri = "docker://docker.io/paketobuildpacks/environment-variables:4.10.0" 43 | 44 | [[dependencies]] 45 | uri = "docker://docker.io/paketobuildpacks/ca-certificates:3.11.0" 46 | 47 | [[dependencies]] 48 | uri = "docker://docker.io/paketobuildpacks/image-labels:4.11.0" 49 | 50 | [[dependencies]] 51 | uri = "docker://docker.io/paketobuildpacks/watchexec:3.6.0" 52 | 53 | [[targets]] 54 | arch = "amd64" 55 | os = "linux" 56 | 57 | [[targets]] 58 | arch = "arm64" 59 | os = "linux" 60 | -------------------------------------------------------------------------------- /.github/labels.yml: -------------------------------------------------------------------------------- 1 | - name: status/possible-priority 2 | description: This issue is ready to work and should be considered as a potential priority 3 | color: F9D0C4 4 | - name: status/prioritized 5 | description: This issue has been triaged and resolving it is a priority 6 | color: BFD4F2 7 | - name: status/blocked 8 | description: This issue has been triaged and resolving it is blocked on some other issue 9 | color: 848978 10 | - name: bug 11 | description: Something isn't working 12 | color: d73a4a 13 | - name: enhancement 14 | description: A new feature or request 15 | color: a2eeef 16 | - name: documentation 17 | description: This issue relates to writing documentation 18 | color: D4C5F9 19 | - name: help wanted 20 | description: Extra attention is needed 21 | color: 008672 22 | - name: semver:major 23 | description: A change requiring a major version bump 24 | color: 6b230e 25 | - name: semver:minor 26 | description: A change requiring a minor version bump 27 | color: cc6749 28 | - name: semver:patch 29 | description: A change requiring a patch version bump 30 | color: f9d0c4 31 | - name: good first issue 32 | description: A good first issue to get started with 33 | color: d3fc03 34 | - name: "failure:release" 35 | description: An issue filed automatically when a release workflow run fails 36 | color: f00a0a 37 | - name: "failure:push" 38 | description: An issue filed automatically when a push buildpackage workflow run fails 39 | color: f00a0a 40 | - name: "failure:update-buildpack-toml" 41 | description: An issue filed automatically when a buildpack.toml update workflow run fails 42 | color: f00a0a 43 | - name: "failure:update-github-config" 44 | description: An issue filed automatically when a github config update workflow run fails 45 | color: f00a0a 46 | - name: "failure:approve-bot-pr" 47 | description: An issue filed automatically when a PR auto-approve workflow run fails 48 | color: f00a0a 49 | -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/bindings/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFeTCCA2GgAwIBAgICB+UwDQYJKoZIhvcNAQELBQAwTjEaMBgGA1UEChMRUGFr 3 | ZXRvIEJ1aWxkcGFja3MxMDAuBgNVBAMTJ1Bha2V0byBCdWlsZHBhY2tzIENlcnRp 4 | ZmljYXRlIEF1dGhvcml0eTAeFw0yMTAzMDIxNjU5MjRaFw0zMTAzMDIxNjU5MjRa 5 | ME4xGjAYBgNVBAoTEVBha2V0byBCdWlsZHBhY2tzMTAwLgYDVQQDEydQYWtldG8g 6 | QnVpbGRwYWNrcyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEB 7 | AQUAA4ICDwAwggIKAoICAQDGQS7V1sKolBHl7WV19S3sDZwUCP4BR0UrZqvR2hmm 8 | v0D1tsxmVDepX0hbQOMUq9oiSsDga2uNrVfvLNC81PZF+KePgTawdIVCF6eSPZyY 9 | muVDorvd7UGpKdx1AL3Ez+QhLj9PGP1EW6nU7oD/6XzJWeRkNZWxPNP0Ev6fChfN 10 | qKXkPJYNHPrq3G7LQ6do7oaexXEOMd+lxLtUObSXyzMQn50olkxbogLC0ncNb17h 11 | 8f0YzogQnZxe0LIkXTkbq47UJcZyZVXe4Vjuf6YXP8NY8ABW380hSbI/aHR0btD1 12 | mA24ups0XGcqD/4v8LtrEFm1pBC58faDQi435hVvaiuzz9wbhAMh1J18/FbiqnkR 13 | P+l2nEQOButa1F4ClZZ989bhJboW6LSafQRJT4yAzfRuTXBzAWFYJrikdVabfnwZ 14 | z2rZrR4lgj5IklEnTk1DiJVvNP87faTY4L0CZexrjj4YRq0BLvMG7hAkJ/7/5WZK 15 | nNSJf+P7PNyDNWUPR+aN8R411PUG53Mxyi+lumi6eucmLQONCIuI2EdQ4iPP+QR4 16 | 7r1eLS/+Sxn4mifux6GcDbzTrJDHXtaqCFWRyKUdooEo7dJVceJ/lxJLpn8W/enH 17 | OJs8J9IkUjtYizNkfDniIvHQoU3mQZx6P8AzKTJ7XA5i3Xw+YUVaM/z91aQML5sz 18 | xQIDAQABo2EwXzAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYBBQUHAwIG 19 | CCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEwwGrd7Rto0v2qq 20 | YBRt7pucOSjzMA0GCSqGSIb3DQEBCwUAA4ICAQBHNA41hSIBvV7DNy7Winm1ls0R 21 | bICOEawuUOZnKY3Feq1XPsPj1IHaOa4TEwPyOFs89tS5Fig5jIDtpHp+f2dYRknC 22 | eLKjDBZRUWnsuHQIR0MS4k8Bp6ztMiUTdAUSiY+Xv11sa4qGo/NCQdVSzp4wBEBM 23 | ZgnPTF9jU2OjxTufTDhbvYNAbM1l8+aBdF4/88s6D5OEbp3mYhCy8t82x7FKmLee 24 | 9GcQHoZxZjdcJfX5pBtDo9nakeLVbg5PgRUbFsaZyVXQL56VhfEYiM3UzqZCDDuh 25 | L+WU0pFkg0TX1xZ6438N8WD0zg44ObKEORfEvPAxbcKa+Nb8p1WsMKJmbeDDaXib 26 | wu7A+kWa5s4rf9zlDt0Y4wVFNuO602dO6VFyZXg8dcRyjRNa/0w/l4elgOPRonbl 27 | 8P9JY1KtIkZvQ8+f7NwloSGg+/Q0j2XqTSM04TP+RQ92iSNfsm+x8gZotKdUrvUN 28 | /7sLRgJvlJoBQ+bSHveT7r1IXE0zkM8535kYD8UEQ68cqZUEDOwK8qo2n4HY5oQ3 29 | 4BTkHOAEu39Ov6MrgeiSDzINc2eBadJcb5CwTKH17gLGDeQz8H4fRKSv2+6Pty6H 30 | esKmgqCE28Xnaz3snOEYSRfnG0+o5rgrXFUd0qAjpiu/rqCOXl9TeSEUM+YvjjRC 31 | /HNPsIbBVFyt0n7mYw== 32 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/client_certs/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFeTCCA2GgAwIBAgICB+UwDQYJKoZIhvcNAQELBQAwTjEaMBgGA1UEChMRUGFr 3 | ZXRvIEJ1aWxkcGFja3MxMDAuBgNVBAMTJ1Bha2V0byBCdWlsZHBhY2tzIENlcnRp 4 | ZmljYXRlIEF1dGhvcml0eTAeFw0yMTAzMDIxNjU5MjRaFw0zMTAzMDIxNjU5MjRa 5 | ME4xGjAYBgNVBAoTEVBha2V0byBCdWlsZHBhY2tzMTAwLgYDVQQDEydQYWtldG8g 6 | QnVpbGRwYWNrcyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEB 7 | AQUAA4ICDwAwggIKAoICAQDGQS7V1sKolBHl7WV19S3sDZwUCP4BR0UrZqvR2hmm 8 | v0D1tsxmVDepX0hbQOMUq9oiSsDga2uNrVfvLNC81PZF+KePgTawdIVCF6eSPZyY 9 | muVDorvd7UGpKdx1AL3Ez+QhLj9PGP1EW6nU7oD/6XzJWeRkNZWxPNP0Ev6fChfN 10 | qKXkPJYNHPrq3G7LQ6do7oaexXEOMd+lxLtUObSXyzMQn50olkxbogLC0ncNb17h 11 | 8f0YzogQnZxe0LIkXTkbq47UJcZyZVXe4Vjuf6YXP8NY8ABW380hSbI/aHR0btD1 12 | mA24ups0XGcqD/4v8LtrEFm1pBC58faDQi435hVvaiuzz9wbhAMh1J18/FbiqnkR 13 | P+l2nEQOButa1F4ClZZ989bhJboW6LSafQRJT4yAzfRuTXBzAWFYJrikdVabfnwZ 14 | z2rZrR4lgj5IklEnTk1DiJVvNP87faTY4L0CZexrjj4YRq0BLvMG7hAkJ/7/5WZK 15 | nNSJf+P7PNyDNWUPR+aN8R411PUG53Mxyi+lumi6eucmLQONCIuI2EdQ4iPP+QR4 16 | 7r1eLS/+Sxn4mifux6GcDbzTrJDHXtaqCFWRyKUdooEo7dJVceJ/lxJLpn8W/enH 17 | OJs8J9IkUjtYizNkfDniIvHQoU3mQZx6P8AzKTJ7XA5i3Xw+YUVaM/z91aQML5sz 18 | xQIDAQABo2EwXzAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYBBQUHAwIG 19 | CCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEwwGrd7Rto0v2qq 20 | YBRt7pucOSjzMA0GCSqGSIb3DQEBCwUAA4ICAQBHNA41hSIBvV7DNy7Winm1ls0R 21 | bICOEawuUOZnKY3Feq1XPsPj1IHaOa4TEwPyOFs89tS5Fig5jIDtpHp+f2dYRknC 22 | eLKjDBZRUWnsuHQIR0MS4k8Bp6ztMiUTdAUSiY+Xv11sa4qGo/NCQdVSzp4wBEBM 23 | ZgnPTF9jU2OjxTufTDhbvYNAbM1l8+aBdF4/88s6D5OEbp3mYhCy8t82x7FKmLee 24 | 9GcQHoZxZjdcJfX5pBtDo9nakeLVbg5PgRUbFsaZyVXQL56VhfEYiM3UzqZCDDuh 25 | L+WU0pFkg0TX1xZ6438N8WD0zg44ObKEORfEvPAxbcKa+Nb8p1WsMKJmbeDDaXib 26 | wu7A+kWa5s4rf9zlDt0Y4wVFNuO602dO6VFyZXg8dcRyjRNa/0w/l4elgOPRonbl 27 | 8P9JY1KtIkZvQ8+f7NwloSGg+/Q0j2XqTSM04TP+RQ92iSNfsm+x8gZotKdUrvUN 28 | /7sLRgJvlJoBQ+bSHveT7r1IXE0zkM8535kYD8UEQ68cqZUEDOwK8qo2n4HY5oQ3 29 | 4BTkHOAEu39Ov6MrgeiSDzINc2eBadJcb5CwTKH17gLGDeQz8H4fRKSv2+6Pty6H 30 | esKmgqCE28Xnaz3snOEYSRfnG0+o5rgrXFUd0qAjpiu/rqCOXl9TeSEUM+YvjjRC 31 | /HNPsIbBVFyt0n7mYw== 32 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/conda/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 31 | o7kYPHxnraAtNlmQEDyEQ9s= 32 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/pip/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 31 | o7kYPHxnraAtNlmQEDyEQ9s= 32 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/pipenv/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 31 | o7kYPHxnraAtNlmQEDyEQ9s= 32 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/client_certs/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 31 | o7kYPHxnraAtNlmQEDyEQ9s= 32 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/no_package_manager/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 31 | o7kYPHxnraAtNlmQEDyEQ9s= 32 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python Paketo Buildpack 2 | 3 | ## `gcr.io/paketo-buildpacks/python` 4 | 5 | The Python Paketo Buildpack provides a set of collaborating buildpacks to build a Python-based application 6 | These buildpacks include: 7 | - [CPython CNB](https://github.com/paketo-buildpacks/cpython) 8 | - [Pipenv CNB](https://github.com/paketo-buildpacks/pipenv) 9 | - [Pipenv Install CNB](https://github.com/paketo-buildpacks/pipenv-install) 10 | - [Pip CNB](https://github.com/paketo-buildpacks/pip) 11 | - [Pip Install CNB](https://github.com/paketo-buildpacks/pip-install) 12 | - [Miniconda CNB](https://github.com/paketo-buildpacks/miniconda) 13 | - [Conda Env Update CNB](https://github.com/paketo-buildpacks/conda-env-update) 14 | - [Poetry CNB](https://github.com/paketo-buildpacks/poetry) 15 | - [Poetry Install CNB](https://github.com/paketo-buildpacks/poetry-install) 16 | - [Poetry Run CNB](https://github.com/paketo-buildpacks/poetry-run) 17 | - [Python Start CNB](https://github.com/paketo-buildpacks/python-start) 18 | 19 | Additionally, the following utility buildpacks are included for all application types 20 | - [CA Certificates CNB](https://github.com/paketo-buildpacks/ca-certificates) 21 | - [Watchexec CNB](https://github.com/paketo-buildpacks/watchexec) 22 | - [Procfile CNB](https://github.com/paketo-buildpacks/procfile) 23 | - [Environment Variables CNB](https://github.com/paketo-buildpacks/environment-variables) 24 | - [Image Labels CNB](https://github.com/paketo-buildpacks/image-labels) 25 | 26 | The buildpack supports building simple Python applications or applications which 27 | utilize either [Conda](https://conda.io), 28 | [Pipenv](https://pypi.org/project/pipenv/), 29 | [Pip](https://pip.pypa.io/), 30 | or [Poetry](https://python-poetry.org/) for managing their dependencies. 31 | 32 | Check out the [Python Paketo Buildpack docs](https://paketo.io/docs/howto/python/) for sample usage and more information. 33 | 34 | #### The Python buildpack is compatible with the following builder(s): 35 | - [Paketo Jammy Full Builder](https://github.com/paketo-buildpacks/builder-jammy-full) 36 | - [Paketo Bionic Full Builder](https://github.com/paketo-buildpacks/full-builder) 37 | - [Paketo Jammy Base Builder](https://github.com/paketo-buildpacks/builder-jammy-base) 38 | - [Paketo Bionic Base Builder](https://github.com/paketo-buildpacks/base-builder) 39 | -------------------------------------------------------------------------------- /.github/workflows/test-pull-request.yml: -------------------------------------------------------------------------------- 1 | name: Test Pull Request 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | concurrency: 9 | # only one instance of test suite per PR at one time 10 | group: pr-${{ github.event.number }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | builders: 15 | name: Get Builders for Testing 16 | runs-on: ubuntu-24.04 17 | outputs: 18 | builders: ${{ steps.builders.outputs.builders }} 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v6 22 | - name: Get builders from integration.json 23 | id: builders 24 | run: | 25 | source "${{ github.workspace }}/scripts/.util/builders.sh" 26 | 27 | builders="$(util::builders::list "${{ github.workspace }}/integration.json")" 28 | printf "Output: %s\n" "${builders}" 29 | printf "builders=%s\n" "${builders}" >> "$GITHUB_OUTPUT" 30 | 31 | integration: 32 | name: Integration Tests with Builders 33 | runs-on: ubuntu-24.04 34 | needs: [builders] 35 | strategy: 36 | matrix: 37 | builder: ${{ fromJSON(needs.builders.outputs.builders) }} 38 | fail-fast: false # don't cancel all test jobs when one fails 39 | steps: 40 | - name: Checkout 41 | uses: actions/checkout@v6 42 | 43 | - name: Setup Go 44 | uses: actions/setup-go@v6 45 | with: 46 | go-version-file: go.mod 47 | 48 | - name: Run Integration Tests 49 | env: 50 | TMPDIR: "${{ runner.temp }}" 51 | GIT_TOKEN: ${{ github.token }} 52 | run: ./scripts/integration.sh --builder ${{ matrix.builder }} 53 | 54 | roundup: 55 | name: Integration Tests 56 | if: ${{ always() }} 57 | runs-on: ubuntu-24.04 58 | needs: integration 59 | steps: 60 | - run: | 61 | result="${{ needs.integration.result }}" 62 | if [[ $result == "success" ]]; then 63 | echo "Integration tests passed against all builders" 64 | exit 0 65 | else 66 | echo "Integration tests failed on one or more builders" 67 | exit 1 68 | fi 69 | 70 | upload: 71 | name: Upload Workflow Event Payload 72 | runs-on: ubuntu-24.04 73 | steps: 74 | - name: Upload Artifact 75 | uses: actions/upload-artifact@v6 76 | with: 77 | name: event-payload 78 | path: ${{ github.event_path }} 79 | -------------------------------------------------------------------------------- /.github/workflows/update-github-config.yml: -------------------------------------------------------------------------------- 1 | name: Update shared github-config 2 | 3 | on: 4 | schedule: 5 | - cron: '20 17 * * *' # daily at 17:20 UTC 6 | workflow_dispatch: {} 7 | 8 | concurrency: github_config_update 9 | 10 | jobs: 11 | build: 12 | name: Create PR to update shared files 13 | runs-on: ubuntu-24.04 14 | steps: 15 | 16 | - name: Checkout 17 | uses: actions/checkout@v6 18 | with: 19 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }} 20 | 21 | - name: Checkout github-config 22 | uses: actions/checkout@v6 23 | with: 24 | repository: paketo-buildpacks/github-config 25 | path: github-config 26 | 27 | - name: Checkout Branch 28 | uses: paketo-buildpacks/github-config/actions/pull-request/checkout-branch@main 29 | with: 30 | branch: automation/github-config/update 31 | 32 | - name: Run the sync action 33 | uses: paketo-buildpacks/github-config/actions/sync@main 34 | with: 35 | workspace: /github/workspace 36 | config: /github/workspace/github-config/language-family 37 | 38 | - name: Cleanup 39 | run: rm -rf github-config 40 | 41 | - name: Commit 42 | id: commit 43 | uses: paketo-buildpacks/github-config/actions/pull-request/create-commit@main 44 | with: 45 | message: "Updating github-config" 46 | pathspec: "." 47 | keyid: ${{ secrets.PAKETO_BOT_GPG_SIGNING_KEY_ID }} 48 | key: ${{ secrets.PAKETO_BOT_GPG_SIGNING_KEY }} 49 | 50 | - name: Push Branch 51 | if: ${{ steps.commit.outputs.commit_sha != '' }} 52 | uses: paketo-buildpacks/github-config/actions/pull-request/push-branch@main 53 | with: 54 | branch: automation/github-config/update 55 | 56 | - name: Open Pull Request 57 | if: ${{ steps.commit.outputs.commit_sha != '' }} 58 | uses: paketo-buildpacks/github-config/actions/pull-request/open@main 59 | with: 60 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }} 61 | title: "Updates github-config" 62 | branch: automation/github-config/update 63 | 64 | failure: 65 | name: Alert on Failure 66 | runs-on: ubuntu-24.04 67 | needs: [build] 68 | if: ${{ always() && needs.build.result == 'failure' }} 69 | steps: 70 | - name: File Failure Alert Issue 71 | uses: paketo-buildpacks/github-config/actions/issue/file@main 72 | with: 73 | token: ${{ secrets.GITHUB_TOKEN }} 74 | repo: ${{ github.repository }} 75 | label: "failure:update-github-config" 76 | comment_if_exists: true 77 | issue_title: "Failure: Update GitHub config workflow" 78 | issue_body: | 79 | Update GitHub config workflow [failed](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}). 80 | comment_body: | 81 | Another failure occurred: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} 82 | -------------------------------------------------------------------------------- /.github/workflows/approve-bot-pr.yml: -------------------------------------------------------------------------------- 1 | name: Approve Bot PRs and Enable Auto-Merge 2 | 3 | on: 4 | workflow_run: 5 | workflows: ["Test Pull Request"] 6 | types: 7 | - completed 8 | 9 | jobs: 10 | download: 11 | name: Download PR Artifact 12 | if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }} 13 | runs-on: ubuntu-24.04 14 | outputs: 15 | pr-author: ${{ steps.pr-data.outputs.author }} 16 | pr-number: ${{ steps.pr-data.outputs.number }} 17 | steps: 18 | - name: 'Download artifact' 19 | uses: paketo-buildpacks/github-config/actions/pull-request/download-artifact@main 20 | with: 21 | name: "event-payload" 22 | repo: ${{ github.repository }} 23 | run_id: ${{ github.event.workflow_run.id }} 24 | workspace: "/github/workspace" 25 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }} 26 | - id: pr-data 27 | run: | 28 | echo "author=$(cat event.json | jq -r '.pull_request.user.login')" >> "$GITHUB_OUTPUT" 29 | echo "number=$(cat event.json | jq -r '.pull_request.number')" >> "$GITHUB_OUTPUT" 30 | 31 | approve: 32 | name: Approve Bot PRs 33 | needs: download 34 | if: ${{ needs.download.outputs.pr-author == 'paketo-bot' || needs.download.outputs.pr-author == 'dependabot[bot]' }} 35 | runs-on: ubuntu-24.04 36 | steps: 37 | - name: Check Commit Verification 38 | id: unverified-commits 39 | uses: paketo-buildpacks/github-config/actions/pull-request/check-unverified-commits@main 40 | with: 41 | token: ${{ secrets.PAKETO_BOT_REVIEWER_GITHUB_TOKEN }} 42 | repo: ${{ github.repository }} 43 | number: ${{ needs.download.outputs.pr-number }} 44 | 45 | - name: Check for Human Commits 46 | id: human-commits 47 | uses: paketo-buildpacks/github-config/actions/pull-request/check-human-commits@main 48 | with: 49 | token: ${{ secrets.PAKETO_BOT_REVIEWER_GITHUB_TOKEN }} 50 | repo: ${{ github.repository }} 51 | number: ${{ needs.download.outputs.pr-number }} 52 | 53 | - name: Checkout 54 | if: steps.human-commits.outputs.human_commits == 'false' && steps.unverified-commits.outputs.unverified_commits == 'false' 55 | uses: actions/checkout@v6 56 | 57 | - name: Approve 58 | if: steps.human-commits.outputs.human_commits == 'false' && steps.unverified-commits.outputs.unverified_commits == 'false' 59 | uses: paketo-buildpacks/github-config/actions/pull-request/approve@main 60 | with: 61 | token: ${{ secrets.PAKETO_BOT_REVIEWER_GITHUB_TOKEN }} 62 | number: ${{ needs.download.outputs.pr-number }} 63 | 64 | - name: Enable Auto-Merge 65 | if: steps.human-commits.outputs.human_commits == 'false' && steps.unverified-commits.outputs.unverified_commits == 'false' 66 | run: | 67 | gh pr merge ${{ needs.download.outputs.pr-number }} --auto --rebase 68 | env: 69 | GITHUB_TOKEN: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }} 70 | -------------------------------------------------------------------------------- /.github/workflows/update-buildpack-toml.yml: -------------------------------------------------------------------------------- 1 | name: Update buildpack.toml 2 | 3 | on: 4 | schedule: 5 | - cron: '1 6 * * *' # daily at 06:01 UTC 6 | workflow_dispatch: {} 7 | 8 | concurrency: buildpack_update 9 | 10 | jobs: 11 | update-buildpack-toml: 12 | runs-on: ubuntu-24.04 13 | name: Update buildpack.toml 14 | steps: 15 | 16 | - name: Checkout 17 | uses: actions/checkout@v6 18 | 19 | - name: Checkout Branch 20 | uses: paketo-buildpacks/github-config/actions/pull-request/checkout-branch@main 21 | with: 22 | branch: automation/buildpack.toml/update 23 | 24 | - name: Update buildpack.toml 25 | id: update 26 | uses: paketo-buildpacks/github-config/actions/buildpack/update@main 27 | 28 | - name: Commit 29 | id: commit 30 | uses: paketo-buildpacks/github-config/actions/pull-request/create-commit@main 31 | with: 32 | message: "Updating buildpacks in buildpack.toml" 33 | pathspec: "." 34 | keyid: ${{ secrets.PAKETO_BOT_GPG_SIGNING_KEY_ID }} 35 | key: ${{ secrets.PAKETO_BOT_GPG_SIGNING_KEY }} 36 | 37 | - name: Push Branch 38 | if: ${{ steps.commit.outputs.commit_sha != '' }} 39 | uses: paketo-buildpacks/github-config/actions/pull-request/push-branch@main 40 | with: 41 | branch: automation/buildpack.toml/update 42 | 43 | - name: Open Pull Request (no semver label) 44 | if: ${{ steps.commit.outputs.commit_sha != '' && steps.update.outputs.semver_bump == '' }} 45 | uses: paketo-buildpacks/github-config/actions/pull-request/open@main 46 | with: 47 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }} 48 | title: "Updates buildpacks in buildpack.toml" 49 | branch: automation/buildpack.toml/update 50 | 51 | - name: Open Pull Request 52 | if: ${{ steps.commit.outputs.commit_sha != '' && steps.update.outputs.semver_bump != '' }} 53 | uses: paketo-buildpacks/github-config/actions/pull-request/open@main 54 | with: 55 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }} 56 | title: "Updates buildpacks in buildpack.toml" 57 | branch: automation/buildpack.toml/update 58 | label: "semver:${{ steps.update.outputs.semver_bump }}" 59 | 60 | failure: 61 | name: Alert on Failure 62 | runs-on: ubuntu-24.04 63 | needs: [update-buildpack-toml] 64 | if: ${{ always() && needs.update-buildpack-toml.result == 'failure' }} 65 | steps: 66 | - name: File Failure Alert Issue 67 | uses: paketo-buildpacks/github-config/actions/issue/file@main 68 | with: 69 | token: ${{ secrets.GITHUB_TOKEN }} 70 | repo: ${{ github.repository }} 71 | label: "failure:update-buildpack-toml" 72 | comment_if_exists: true 73 | issue_title: "Failure: Update Buildpack TOML workflow" 74 | issue_body: | 75 | Update Buildpack TOML workflow [failed](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}). 76 | comment_body: | 77 | Another failure occurred: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} 78 | -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/pip/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 51 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/conda/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 51 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/pipenv/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 51 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/client_certs/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 51 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /integration/testdata/ca_cert_apps/no_package_manager/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 51 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /.github/workflows/update-go-mod-version.yml: -------------------------------------------------------------------------------- 1 | name: Update Go version 2 | 3 | on: 4 | schedule: 5 | - cron: '13 4 * * MON' # every monday at 4:13 UTC 6 | workflow_dispatch: 7 | 8 | concurrency: update-go 9 | 10 | jobs: 11 | update-go: 12 | name: Update go toolchain in go.mod 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Check out code 16 | uses: actions/checkout@v6 17 | - name: Checkout PR Branch 18 | uses: paketo-buildpacks/github-config/actions/pull-request/checkout-branch@main 19 | with: 20 | branch: automation/go-mod-update/update-main 21 | - name: Setup Go 22 | id: setup-go 23 | uses: actions/setup-go@v6 24 | # Fetching the latest stable Go version 25 | with: 26 | go-version: stable 27 | - name: Get current go toolchain version 28 | id: current-go-version 29 | uses: paketo-buildpacks/github-config/actions/update-go-mod-version@main 30 | with: 31 | go-version: ${{ steps.setup-go.outputs.go-version }} 32 | - name: Go mod tidy 33 | run: | 34 | #!/usr/bin/env bash 35 | set -euo pipefail 36 | shopt -s inherit_errexit 37 | 38 | echo "Before running go mod tidy" 39 | echo "head -n10 go.mod " 40 | head -n10 go.mod 41 | 42 | echo "git diff" 43 | git diff 44 | 45 | echo "Running go mod tidy" 46 | go mod tidy 47 | 48 | echo "After running go mod tidy" 49 | echo "head -n10 go.mod " 50 | head -n10 go.mod 51 | 52 | echo "git diff" 53 | git diff 54 | - name: Commit 55 | id: commit 56 | uses: paketo-buildpacks/github-config/actions/pull-request/create-commit@main 57 | with: 58 | message: "Updates go mod version to ${{ steps.setup-go.outputs.go-version }}" 59 | pathspec: "." 60 | keyid: ${{ secrets.PAKETO_BOT_GPG_SIGNING_KEY_ID }} 61 | key: ${{ secrets.PAKETO_BOT_GPG_SIGNING_KEY }} 62 | 63 | - name: Push Branch 64 | if: ${{ steps.commit.outputs.commit_sha != '' }} 65 | uses: paketo-buildpacks/github-config/actions/pull-request/push-branch@main 66 | with: 67 | branch: automation/go-mod-update/update-main 68 | 69 | - name: Open Pull Request 70 | if: ${{ steps.commit.outputs.commit_sha != '' }} 71 | uses: paketo-buildpacks/github-config/actions/pull-request/open@main 72 | with: 73 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }} 74 | title: "Updates go mod version to ${{ steps.setup-go.outputs.go-version }}" 75 | branch: automation/go-mod-update/update-main 76 | 77 | failure: 78 | name: Alert on Failure 79 | runs-on: ubuntu-24.04 80 | needs: [update-go] 81 | if: ${{ always() && needs.update-go.result == 'failure' }} 82 | steps: 83 | - name: File Failure Alert Issue 84 | uses: paketo-buildpacks/github-config/actions/issue/file@main 85 | with: 86 | token: ${{ secrets.GITHUB_TOKEN }} 87 | repo: ${{ github.repository }} 88 | label: "failure:update-go-version" 89 | comment_if_exists: true 90 | issue_title: "Failure: Update Go Mod Version workflow" 91 | issue_body: | 92 | Update Go Mod Version workflow [failed](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}). 93 | comment_body: | 94 | Another failure occurred: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} 95 | -------------------------------------------------------------------------------- /integration/poetry_run_test.go: -------------------------------------------------------------------------------- 1 | package integration_test 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "os" 8 | "path/filepath" 9 | "testing" 10 | 11 | "github.com/paketo-buildpacks/occam" 12 | "github.com/sclevine/spec" 13 | 14 | . "github.com/onsi/gomega" 15 | . "github.com/paketo-buildpacks/occam/matchers" 16 | ) 17 | 18 | func testPoetryRun(t *testing.T, context spec.G, it spec.S) { 19 | var ( 20 | Expect = NewWithT(t).Expect 21 | Eventually = NewWithT(t).Eventually 22 | 23 | pack occam.Pack 24 | docker occam.Docker 25 | ) 26 | 27 | it.Before(func() { 28 | pack = occam.NewPack() 29 | docker = occam.NewDocker() 30 | }) 31 | 32 | context("when building a poetry app with a poetry run script", func() { 33 | var ( 34 | image occam.Image 35 | container occam.Container 36 | 37 | name string 38 | source string 39 | ) 40 | 41 | it.Before(func() { 42 | var err error 43 | name, err = occam.RandomName() 44 | Expect(err).NotTo(HaveOccurred()) 45 | }) 46 | 47 | it.After(func() { 48 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed()) 49 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed()) 50 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed()) 51 | Expect(os.RemoveAll(source)).To(Succeed()) 52 | }) 53 | 54 | it("creates a working OCI image with a start command", func() { 55 | var err error 56 | source, err = occam.Source(filepath.Join("testdata", "poetry-run")) 57 | Expect(err).NotTo(HaveOccurred()) 58 | 59 | var logs fmt.Stringer 60 | image, logs, err = pack.WithNoColor().Build. 61 | WithBuildpacks(pythonBuildpack). 62 | WithPullPolicy("never"). 63 | WithEnv(map[string]string{ 64 | "BPE_SOME_VARIABLE": "some-value", 65 | "BP_IMAGE_LABELS": "some-label=some-value", 66 | "BP_LIVE_RELOAD_ENABLED": "true", 67 | }). 68 | Execute(name, source) 69 | Expect(err).NotTo(HaveOccurred(), logs.String()) 70 | 71 | container, err = docker.Container.Run. 72 | WithEnv(map[string]string{"PORT": "8080"}). 73 | WithPublish("8080"). 74 | WithPublishAll(). 75 | Execute(image.ID) 76 | Expect(err).NotTo(HaveOccurred()) 77 | 78 | Eventually(container).Should(BeAvailable()) 79 | 80 | response, err := http.Get(fmt.Sprintf("http://localhost:%s", container.HostPort("8080"))) 81 | Expect(err).NotTo(HaveOccurred()) 82 | defer func() { Expect(response.Body.Close()).ToNot(HaveOccurred()) }() 83 | 84 | Expect(response.StatusCode).To(Equal(http.StatusOK)) 85 | 86 | content, err := io.ReadAll(response.Body) 87 | Expect(err).NotTo(HaveOccurred()) 88 | Expect(string(content)).To(ContainSubstring("Hello, World!")) 89 | 90 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) 91 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CPython"))) 92 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pip"))) 93 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Poetry"))) 94 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Poetry Install"))) 95 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Poetry Run"))) 96 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Environment Variables"))) 97 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Image Labels"))) 98 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Watchexec"))) 99 | 100 | Expect(image.Buildpacks[7].Key).To(Equal("paketo-buildpacks/environment-variables")) 101 | Expect(image.Buildpacks[7].Layers["environment-variables"].Metadata["variables"]).To(Equal(map[string]interface{}{"SOME_VARIABLE": "some-value"})) 102 | Expect(image.Labels["some-label"]).To(Equal("some-value")) 103 | }) 104 | }) 105 | } 106 | -------------------------------------------------------------------------------- /integration/poetry_dep_only_test.go: -------------------------------------------------------------------------------- 1 | package integration_test 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "os" 8 | "path/filepath" 9 | "testing" 10 | 11 | "github.com/paketo-buildpacks/occam" 12 | "github.com/sclevine/spec" 13 | 14 | . "github.com/onsi/gomega" 15 | . "github.com/paketo-buildpacks/occam/matchers" 16 | ) 17 | 18 | func testPoetryDepOnly(t *testing.T, context spec.G, it spec.S) { 19 | var ( 20 | Expect = NewWithT(t).Expect 21 | Eventually = NewWithT(t).Eventually 22 | 23 | pack occam.Pack 24 | docker occam.Docker 25 | ) 26 | 27 | it.Before(func() { 28 | pack = occam.NewPack() 29 | docker = occam.NewDocker() 30 | }) 31 | 32 | context("when building an app with poetry dependency management", func() { 33 | var ( 34 | image occam.Image 35 | container occam.Container 36 | 37 | name string 38 | source string 39 | ) 40 | 41 | it.Before(func() { 42 | var err error 43 | name, err = occam.RandomName() 44 | Expect(err).NotTo(HaveOccurred()) 45 | }) 46 | 47 | it.After(func() { 48 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed()) 49 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed()) 50 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed()) 51 | Expect(os.RemoveAll(source)).To(Succeed()) 52 | }) 53 | 54 | it("creates a working OCI image with a start command", func() { 55 | var err error 56 | source, err = occam.Source(filepath.Join("testdata", "poetry-dep-only")) 57 | Expect(err).NotTo(HaveOccurred()) 58 | 59 | var logs fmt.Stringer 60 | image, logs, err = pack.WithNoColor().WithVerbose().Build. 61 | WithBuildpacks(pythonBuildpack). 62 | WithPullPolicy("never"). 63 | WithEnv(map[string]string{ 64 | "BPE_SOME_VARIABLE": "some-value", 65 | "BP_IMAGE_LABELS": "some-label=some-value", 66 | "BP_LIVE_RELOAD_ENABLED": "true", 67 | }). 68 | Execute(name, source) 69 | Expect(err).NotTo(HaveOccurred(), logs.String()) 70 | 71 | container, err = docker.Container.Run. 72 | WithEnv(map[string]string{"PORT": "8080"}). 73 | WithPublish("8080"). 74 | WithPublishAll(). 75 | Execute(image.ID) 76 | Expect(err).NotTo(HaveOccurred()) 77 | 78 | Eventually(container).Should(BeAvailable()) 79 | 80 | response, err := http.Get(fmt.Sprintf("http://localhost:%s", container.HostPort("8080"))) 81 | Expect(err).NotTo(HaveOccurred()) 82 | defer func() { Expect(response.Body.Close()).ToNot(HaveOccurred()) }() 83 | 84 | Expect(response.StatusCode).To(Equal(http.StatusOK)) 85 | 86 | content, err := io.ReadAll(response.Body) 87 | Expect(err).NotTo(HaveOccurred()) 88 | Expect(string(content)).To(ContainSubstring("Hello, World!")) 89 | 90 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) 91 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Watchexec"))) 92 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CPython"))) 93 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pip"))) 94 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Poetry"))) 95 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Poetry Install"))) 96 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) 97 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Procfile"))) 98 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Environment Variables"))) 99 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Image Labels"))) 100 | 101 | Expect(image.Buildpacks[8].Key).To(Equal("paketo-buildpacks/environment-variables")) 102 | Expect(image.Buildpacks[8].Layers["environment-variables"].Metadata["variables"]).To(Equal(map[string]interface{}{"SOME_VARIABLE": "some-value"})) 103 | Expect(image.Labels["some-label"]).To(Equal("some-value")) 104 | }) 105 | }) 106 | } 107 | -------------------------------------------------------------------------------- /scripts/publish.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | set -o pipefail 5 | 6 | readonly ROOT_DIR="$(cd "$(dirname "${0}")/.." && pwd)" 7 | readonly BIN_DIR="${ROOT_DIR}/.bin" 8 | 9 | # shellcheck source=SCRIPTDIR/.util/tools.sh 10 | source "${ROOT_DIR}/scripts/.util/tools.sh" 11 | 12 | # shellcheck source=SCRIPTDIR/.util/print.sh 13 | source "${ROOT_DIR}/scripts/.util/print.sh" 14 | 15 | function main { 16 | local archive_path image_ref token 17 | token="" 18 | 19 | while [[ "${#}" != 0 ]]; do 20 | case "${1}" in 21 | --archive-path | -a) 22 | archive_path="${2}" 23 | shift 2 24 | ;; 25 | 26 | --image-ref | -i) 27 | image_ref="${2}" 28 | shift 2 29 | ;; 30 | 31 | --token | -t) 32 | token="${2}" 33 | shift 2 34 | ;; 35 | 36 | --help | -h) 37 | shift 1 38 | usage 39 | exit 0 40 | ;; 41 | 42 | "") 43 | # skip if the argument is empty 44 | shift 1 45 | ;; 46 | 47 | *) 48 | util::print::error "unknown argument \"${1}\"" 49 | ;; 50 | esac 51 | done 52 | 53 | if [[ -z "${image_ref:-}" ]]; then 54 | usage 55 | util::print::error "--image-ref is required" 56 | fi 57 | 58 | if [[ -z "${archive_path:-}" ]]; then 59 | util::print::info "Using default archive path: ${ROOT_DIR}/build/buildpack-release-artifact.tgz" 60 | archive_path="${ROOT_DIR}/build/buildpack-release-artifact.tgz" 61 | else 62 | archive_path="${archive_path}" 63 | fi 64 | 65 | repo::prepare 66 | 67 | tools::install "${token}" 68 | 69 | buildpack::publish "${image_ref}" "${archive_path}" 70 | } 71 | 72 | function usage() { 73 | cat <<-USAGE 74 | Publishes a composite buildpack to a registry. 75 | 76 | OPTIONS 77 | -a, --archive-path Path to the buildpack release artifact (default: ${ROOT_DIR}/build/buildpack-release-artifact.tgz) (optional) 78 | -h, --help Prints the command usage 79 | -i, --image-ref List of image reference to publish to (required) 80 | -t, --token Token used to download assets from GitHub (e.g. jam, pack, etc) (optional) 81 | 82 | USAGE 83 | } 84 | 85 | function repo::prepare() { 86 | util::print::title "Preparing repo..." 87 | 88 | mkdir -p "${BIN_DIR}" 89 | 90 | export PATH="${BIN_DIR}:${PATH}" 91 | } 92 | 93 | function tools::install() { 94 | local token 95 | token="${1}" 96 | 97 | util::tools::pack::install \ 98 | --directory "${BIN_DIR}" \ 99 | --token "${token}" 100 | 101 | util::tools::yj::install \ 102 | --directory "${BIN_DIR}" \ 103 | --token "${token}" 104 | } 105 | 106 | function buildpack::publish() { 107 | local image_ref archive_path tmp_dir 108 | image_ref="${1}" 109 | archive_path="${2}" 110 | 111 | util::print::title "Publishing composite buildpack..." 112 | 113 | util::print::info "Extracting archive..." 114 | tmp_dir=$(mktemp -d -p $ROOT_DIR) 115 | tar -xvf $archive_path -C $tmp_dir 116 | 117 | util::print::info "Publishing buildpack to ${image_ref}" 118 | 119 | current_dir=$(pwd) 120 | cd $tmp_dir 121 | 122 | # If package.toml has no targets we must specify one on the command line, otherwise pack will complain. 123 | # This is here for backward compatibility but eventually all package.toml files should have targets defined. 124 | targets="" 125 | if cat package.toml | yj -tj | jq -r .targets | grep -q null; then 126 | # Use the local architecture to support running locally and in CI, which will be linux/amd64 by default. 127 | arch=$(util::tools::arch) 128 | targets="--target linux/${arch}" 129 | echo "package.toml has no targets so ${targets} will be used" 130 | fi 131 | 132 | pack \ 133 | buildpack package "${image_ref}" \ 134 | --config package.toml \ 135 | --format image \ 136 | --publish \ 137 | ${targets} 138 | 139 | cd $current_dir 140 | rm -rf $tmp_dir 141 | } 142 | 143 | main "${@:-}" 144 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/paketo-buildpacks/python 2 | 3 | go 1.25.5 4 | 5 | require ( 6 | github.com/onsi/gomega v1.38.3 7 | github.com/paketo-buildpacks/occam v0.31.0 8 | github.com/sclevine/spec v1.4.0 9 | ) 10 | 11 | require ( 12 | dario.cat/mergo v1.0.2 // indirect 13 | github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect 14 | github.com/BurntSushi/toml v1.6.0 // indirect 15 | github.com/Microsoft/go-winio v0.6.2 // indirect 16 | github.com/cenkalti/backoff/v4 v4.3.0 // indirect 17 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 18 | github.com/containerd/errdefs v1.0.0 // indirect 19 | github.com/containerd/errdefs/pkg v0.3.0 // indirect 20 | github.com/containerd/log v0.1.0 // indirect 21 | github.com/containerd/platforms v0.2.1 // indirect 22 | github.com/containerd/stargz-snapshotter/estargz v0.18.1 // indirect 23 | github.com/cpuguy83/dockercfg v0.3.2 // indirect 24 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 25 | github.com/distribution/reference v0.6.0 // indirect 26 | github.com/docker/docker v28.5.2+incompatible // indirect 27 | github.com/docker/go-connections v0.6.0 // indirect 28 | github.com/docker/go-units v0.5.0 // indirect 29 | github.com/ebitengine/purego v0.9.1 // indirect 30 | github.com/felixge/httpsnoop v1.0.4 // indirect 31 | github.com/gabriel-vasile/mimetype v1.4.12 // indirect 32 | github.com/go-logr/logr v1.4.3 // indirect 33 | github.com/go-logr/stdr v1.2.2 // indirect 34 | github.com/go-ole/go-ole v1.3.0 // indirect 35 | github.com/google/go-cmp v0.7.0 // indirect 36 | github.com/google/go-containerregistry v0.20.7 // indirect 37 | github.com/google/uuid v1.6.0 // indirect 38 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect 39 | github.com/klauspost/compress v1.18.2 // indirect 40 | github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect 41 | github.com/magiconair/properties v1.8.10 // indirect 42 | github.com/moby/docker-image-spec v1.3.1 // indirect 43 | github.com/moby/go-archive v0.1.0 // indirect 44 | github.com/moby/patternmatcher v0.6.0 // indirect 45 | github.com/moby/sys/sequential v0.6.0 // indirect 46 | github.com/moby/sys/user v0.4.0 // indirect 47 | github.com/moby/sys/userns v0.1.0 // indirect 48 | github.com/moby/term v0.5.2 // indirect 49 | github.com/morikuni/aec v1.1.0 // indirect 50 | github.com/oklog/ulid v1.3.1 // indirect 51 | github.com/oklog/ulid/v2 v2.1.1 // indirect 52 | github.com/opencontainers/go-digest v1.0.0 // indirect 53 | github.com/opencontainers/image-spec v1.1.1 // indirect 54 | github.com/paketo-buildpacks/freezer v0.2.2 // indirect 55 | github.com/paketo-buildpacks/packit/v2 v2.25.3 // indirect 56 | github.com/pkg/errors v0.9.1 // indirect 57 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 58 | github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect 59 | github.com/shirou/gopsutil/v4 v4.25.11 // indirect 60 | github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect 61 | github.com/stretchr/testify v1.11.1 // indirect 62 | github.com/testcontainers/testcontainers-go v0.40.0 // indirect 63 | github.com/tklauser/go-sysconf v0.3.16 // indirect 64 | github.com/tklauser/numcpus v0.11.0 // indirect 65 | github.com/ulikunitz/xz v0.5.15 // indirect 66 | github.com/vbatts/tar-split v0.12.2 // indirect 67 | github.com/yusufpapurcu/wmi v1.2.4 // indirect 68 | go.opentelemetry.io/auto/sdk v1.2.1 // indirect 69 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 // indirect 70 | go.opentelemetry.io/otel v1.39.0 // indirect 71 | go.opentelemetry.io/otel/metric v1.39.0 // indirect 72 | go.opentelemetry.io/otel/trace v1.39.0 // indirect 73 | go.yaml.in/yaml/v3 v3.0.4 // indirect 74 | golang.org/x/crypto v0.46.0 // indirect 75 | golang.org/x/net v0.48.0 // indirect 76 | golang.org/x/sync v0.19.0 // indirect 77 | golang.org/x/sys v0.39.0 // indirect 78 | golang.org/x/text v0.32.0 // indirect 79 | google.golang.org/grpc v1.77.0 // indirect 80 | google.golang.org/protobuf v1.36.11 // indirect 81 | gopkg.in/yaml.v3 v3.0.1 // indirect 82 | ) 83 | -------------------------------------------------------------------------------- /scripts/integration.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | set -o pipefail 5 | 6 | readonly PROGDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 7 | readonly BUILDPACKDIR="$(cd "${PROGDIR}/.." && pwd)" 8 | 9 | # shellcheck source=SCRIPTDIR/.util/tools.sh 10 | source "${PROGDIR}/.util/tools.sh" 11 | 12 | # shellcheck source=SCRIPTDIR/.util/print.sh 13 | source "${PROGDIR}/.util/print.sh" 14 | 15 | # shellcheck source=SCRIPTDIR/.util/builders.sh 16 | source "${PROGDIR}/.util/builders.sh" 17 | 18 | function main() { 19 | local builderArray token 20 | builderArray=() 21 | token="" 22 | 23 | while [[ "${#}" != 0 ]]; do 24 | case "${1}" in 25 | --help|-h) 26 | shift 1 27 | usage 28 | exit 0 29 | ;; 30 | 31 | --builder|-b) 32 | builderArray+=("${2}") 33 | shift 2 34 | ;; 35 | 36 | --token|-t) 37 | token="${2}" 38 | shift 2 39 | ;; 40 | 41 | "") 42 | # skip if the argument is empty 43 | shift 1 44 | ;; 45 | 46 | *) 47 | util::print::error "unknown argument \"${1}\"" 48 | esac 49 | done 50 | 51 | if [[ ! -d "${BUILDPACKDIR}/integration" ]]; then 52 | util::print::warn "** WARNING No Integration tests **" 53 | fi 54 | 55 | tools::install "${token}" 56 | 57 | if [ ${#builderArray[@]} -eq 0 ]; then 58 | util::print::title "No builders provided. Finding builders in integration.json..." 59 | 60 | local builders 61 | builders="$(util::builders::list "${BUILDPACKDIR}/integration.json" | jq -r '.[]' )" 62 | 63 | util::print::info "Found the following builders:" 64 | util::print::info "${builders}" 65 | 66 | # shellcheck disable=SC2206 67 | IFS=$'\n' builderArray=(${builders}) 68 | unset IFS 69 | fi 70 | 71 | local testout 72 | testout=$(mktemp) 73 | for builder in "${builderArray[@]}"; do 74 | util::print::title "Getting images for builder: '${builder}'" 75 | builder_images::pull "${builder}" 76 | 77 | util::print::title "Setting default pack builder image..." 78 | pack config default-builder "${builder}" 79 | 80 | tests::run "${builder}" "${testout}" 81 | done 82 | 83 | util::tools::tests::checkfocus "${testout}" 84 | util::print::success "** GO Test Succeeded with all builders**" 85 | } 86 | 87 | function usage() { 88 | cat <<-USAGE 89 | integration.sh [OPTIONS] 90 | 91 | Runs the integration test suite. 92 | 93 | OPTIONS 94 | --help -h prints the command usage 95 | --builder -b sets the name of the builder(s) that are pulled / used for testing. 96 | Defaults to "builders" array in integration.json, if present. 97 | --token Token used to download assets from GitHub (e.g. jam, pack, etc) (optional) 98 | USAGE 99 | } 100 | 101 | function tools::install() { 102 | local token 103 | token="${1}" 104 | 105 | util::tools::pack::install \ 106 | --directory "${BUILDPACKDIR}/.bin" \ 107 | --token "${token}" 108 | 109 | util::tools::jam::install \ 110 | --directory "${BUILDPACKDIR}/.bin" \ 111 | --token "${token}" 112 | 113 | util::tools::libpak-tools::install \ 114 | --directory "${BUILDPACKDIR}/.bin" 115 | 116 | util::tools::create-package::install \ 117 | --directory "${BUILDPACKDIR}/.bin" 118 | 119 | if [[ -f "${BUILDPACKDIR}/.libbuildpack" ]]; then 120 | util::tools::packager::install \ 121 | --directory "${BUILDPACKDIR}/.bin" 122 | fi 123 | } 124 | 125 | function builder_images::pull() { 126 | local builder 127 | builder="${1}" 128 | 129 | util::print::title "Pulling builder image ${builder}..." 130 | docker pull "${builder}" 131 | 132 | local run_image lifecycle_image 133 | run_image="$( 134 | pack inspect-builder "${builder}" --output json \ 135 | | jq -r '.remote_info.run_images[0].name' 136 | )" 137 | 138 | lifecycle_image="index.docker.io/buildpacksio/lifecycle:$( 139 | pack inspect-builder "${builder}" --output json \ 140 | | jq -r '.remote_info.lifecycle.version' 141 | )" 142 | 143 | util::print::title "Pulling run image..." 144 | docker pull "${run_image}" 145 | 146 | util::print::title "Pulling lifecycle image..." 147 | docker pull "${lifecycle_image}" 148 | } 149 | 150 | function tests::run() { 151 | util::print::title "Run Buildpack Runtime Integration Tests" 152 | util::print::info "Using ${1} as builder..." 153 | 154 | export CGO_ENABLED=0 155 | pushd "${BUILDPACKDIR}" > /dev/null 156 | if GOMAXPROCS="${GOMAXPROCS:-4}" go test -count=1 -timeout 0 ./integration/... -v -run Integration | tee "${2}"; then 157 | util::print::info "** GO Test Succeeded with ${1}**" 158 | else 159 | util::print::error "** GO Test Failed with ${1}**" 160 | fi 161 | popd > /dev/null 162 | } 163 | 164 | main "${@:-}" 165 | -------------------------------------------------------------------------------- /.github/workflows/create-draft-release.yml: -------------------------------------------------------------------------------- 1 | name: Create or Update Draft Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | repository_dispatch: 8 | types: [ version-bump ] 9 | workflow_dispatch: 10 | inputs: 11 | version: 12 | description: 'Version of the release to cut (e.g. 1.2.3)' 13 | required: false 14 | 15 | concurrency: release 16 | 17 | jobs: 18 | builders: 19 | name: Get Builders for Testing 20 | runs-on: ubuntu-24.04 21 | outputs: 22 | builders: ${{ steps.builders.outputs.builders }} 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v6 26 | - name: Get builders from integration.json 27 | id: builders 28 | run: | 29 | source "${{ github.workspace }}/scripts/.util/builders.sh" 30 | 31 | builders="$(util::builders::list "${{ github.workspace }}/integration.json")" 32 | printf "Output: %s\n" "${builders}" 33 | printf "builders=%s\n" "${builders}" >> "$GITHUB_OUTPUT" 34 | integration: 35 | name: Integration Tests 36 | runs-on: ubuntu-24.04 37 | needs: [builders] 38 | strategy: 39 | matrix: 40 | builder: ${{ fromJSON(needs.builders.outputs.builders) }} 41 | fail-fast: false # don't cancel all test jobs when one fails 42 | steps: 43 | - name: Checkout 44 | uses: actions/checkout@v6 45 | - name: Setup Go 46 | uses: actions/setup-go@v6 47 | with: 48 | go-version-file: go.mod 49 | - name: Run Integration Tests 50 | env: 51 | TMPDIR: "${{ runner.temp }}" 52 | GIT_TOKEN: ${{ github.token }} 53 | run: ./scripts/integration.sh --builder ${{ matrix.builder }} 54 | 55 | release: 56 | name: Release 57 | runs-on: ubuntu-24.04 58 | needs: integration 59 | steps: 60 | - name: Checkout 61 | uses: actions/checkout@v6 62 | with: 63 | fetch-tags: true 64 | - name: Reset Draft Release 65 | id: reset 66 | uses: paketo-buildpacks/github-config/actions/release/reset-draft@main 67 | with: 68 | repo: ${{ github.repository }} 69 | token: ${{ github.token }} 70 | - name: Calculate Semver Tag 71 | if: github.event.inputs.version == '' 72 | id: semver 73 | uses: paketo-buildpacks/github-config/actions/tag/calculate-semver@main 74 | with: 75 | repo: ${{ github.repository }} 76 | token: ${{ github.token }} 77 | ref-name: ${{ github.ref_name }} 78 | - name: Set Release Tag 79 | id: tag 80 | run: | 81 | tag="${{ github.event.inputs.version }}" 82 | if [ -z "${tag}" ]; then 83 | tag="${{ steps.semver.outputs.tag }}" 84 | fi 85 | echo "tag=${tag}" >> "$GITHUB_OUTPUT" 86 | - name: Package 87 | run: ./scripts/package.sh --version "${{ steps.tag.outputs.tag }}" 88 | - name: Create Release Notes 89 | id: create-release-notes 90 | uses: paketo-buildpacks/github-config/actions/release/notes@main 91 | with: 92 | repo: ${{ github.repository }} 93 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }} 94 | - name: Create Draft Release 95 | uses: paketo-buildpacks/github-config/actions/release/create@main 96 | with: 97 | repo: ${{ github.repository }} 98 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }} 99 | tag_name: v${{ steps.tag.outputs.tag }} 100 | target_commitish: ${{ github.sha }} 101 | name: v${{ steps.tag.outputs.tag }} 102 | body: ${{ steps.create-release-notes.outputs.release_body }} 103 | draft: true 104 | assets: | 105 | [ 106 | { 107 | "path": "build/buildpackage.cnb", 108 | "name": "${{ github.event.repository.name }}-${{ steps.tag.outputs.tag }}.cnb", 109 | "content_type": "application/x-tar" 110 | }, 111 | { 112 | "path": "build/buildpack-release-artifact.tgz", 113 | "name": "${{ github.event.repository.name }}-${{ steps.tag.outputs.tag }}.tgz", 114 | "content_type": "application/gzip" 115 | } 116 | ] 117 | 118 | failure: 119 | name: Alert on Failure 120 | runs-on: ubuntu-24.04 121 | needs: [ integration, release ] 122 | if: ${{ always() && needs.integration.result == 'failure' || needs.release.result == 'failure' }} 123 | steps: 124 | - name: File Failure Alert Issue 125 | uses: paketo-buildpacks/github-config/actions/issue/file@main 126 | with: 127 | token: ${{ secrets.GITHUB_TOKEN }} 128 | repo: ${{ github.repository }} 129 | label: "failure:release" 130 | comment_if_exists: true 131 | issue_title: "Failure: Create Draft Release workflow" 132 | issue_body: | 133 | Create Draft Release workflow [failed](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}). 134 | comment_body: | 135 | Another failure occurred: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} 136 | -------------------------------------------------------------------------------- /integration/conda_test.go: -------------------------------------------------------------------------------- 1 | package integration_test 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | "fmt" 7 | "io" 8 | "net/http" 9 | "os" 10 | "path/filepath" 11 | "testing" 12 | 13 | "github.com/paketo-buildpacks/occam" 14 | "github.com/sclevine/spec" 15 | 16 | . "github.com/onsi/gomega" 17 | . "github.com/paketo-buildpacks/occam/matchers" 18 | ) 19 | 20 | func testConda(t *testing.T, context spec.G, it spec.S) { 21 | var ( 22 | Expect = NewWithT(t).Expect 23 | Eventually = NewWithT(t).Eventually 24 | 25 | pack occam.Pack 26 | docker occam.Docker 27 | ) 28 | 29 | it.Before(func() { 30 | pack = occam.NewPack() 31 | docker = occam.NewDocker() 32 | }) 33 | 34 | context("when building a conda app", func() { 35 | var ( 36 | image occam.Image 37 | container occam.Container 38 | 39 | name string 40 | source string 41 | ) 42 | 43 | it.Before(func() { 44 | var err error 45 | name, err = occam.RandomName() 46 | Expect(err).NotTo(HaveOccurred()) 47 | }) 48 | 49 | it.After(func() { 50 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed()) 51 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed()) 52 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed()) 53 | Expect(os.RemoveAll(source)).To(Succeed()) 54 | }) 55 | 56 | it("creates a working OCI image with a start command", func() { 57 | var err error 58 | source, err = occam.Source(filepath.Join("testdata", "conda")) 59 | Expect(err).NotTo(HaveOccurred()) 60 | 61 | var logs fmt.Stringer 62 | image, logs, err = pack.WithNoColor().Build. 63 | WithBuildpacks(pythonBuildpack). 64 | WithPullPolicy("never"). 65 | WithEnv(map[string]string{ 66 | "BPE_SOME_VARIABLE": "some-value", 67 | "BP_IMAGE_LABELS": "some-label=some-value", 68 | "BP_LIVE_RELOAD_ENABLED": "true", 69 | }). 70 | Execute(name, source) 71 | Expect(err).NotTo(HaveOccurred(), logs.String()) 72 | 73 | container, err = docker.Container.Run. 74 | WithEnv(map[string]string{"PORT": "8080"}). 75 | WithPublish("8080"). 76 | WithPublishAll(). 77 | Execute(image.ID) 78 | Expect(err).NotTo(HaveOccurred()) 79 | 80 | Eventually(container).Should(BeAvailable()) 81 | 82 | response, err := http.Get(fmt.Sprintf("http://localhost:%s", container.HostPort("8080"))) 83 | Expect(err).NotTo(HaveOccurred()) 84 | defer func() { Expect(response.Body.Close()).ToNot(HaveOccurred()) }() 85 | 86 | Expect(response.StatusCode).To(Equal(http.StatusOK)) 87 | 88 | content, err := io.ReadAll(response.Body) 89 | Expect(err).NotTo(HaveOccurred()) 90 | Expect(string(content)).To(ContainSubstring("Hello, world!")) 91 | 92 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) 93 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Miniconda"))) 94 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Conda Env Update"))) 95 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) 96 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Procfile"))) 97 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Environment Variables"))) 98 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Image Labels"))) 99 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Watchexec"))) 100 | 101 | Expect(image.Buildpacks[6].Key).To(Equal("paketo-buildpacks/environment-variables")) 102 | Expect(image.Buildpacks[6].Layers["environment-variables"].Metadata["variables"]).To(Equal(map[string]interface{}{"SOME_VARIABLE": "some-value"})) 103 | Expect(image.Labels["some-label"]).To(Equal("some-value")) 104 | }) 105 | 106 | context("when using CA certificates", func() { 107 | var client *http.Client 108 | 109 | it.Before(func() { 110 | var err error 111 | source, err = occam.Source(filepath.Join("testdata", "ca_cert_apps")) 112 | Expect(err).NotTo(HaveOccurred()) 113 | 114 | caCert, err := os.ReadFile(filepath.Join(source, "client_certs", "ca.pem")) 115 | Expect(err).NotTo(HaveOccurred()) 116 | 117 | caCertPool := x509.NewCertPool() 118 | caCertPool.AppendCertsFromPEM(caCert) 119 | 120 | cert, err := tls.LoadX509KeyPair( 121 | filepath.Join(source, "client_certs", "cert.pem"), 122 | filepath.Join(source, "client_certs", "key.pem")) 123 | Expect(err).NotTo(HaveOccurred()) 124 | 125 | client = &http.Client{ 126 | Transport: &http.Transport{ 127 | TLSClientConfig: &tls.Config{ 128 | RootCAs: caCertPool, 129 | Certificates: []tls.Certificate{cert}, 130 | MinVersion: tls.VersionTLS12, 131 | }, 132 | }, 133 | } 134 | }) 135 | 136 | it("builds a working OCI image with a start command and uses a client-side CA cert for requests", func() { 137 | var err error 138 | var logs fmt.Stringer 139 | 140 | image, logs, err = pack.WithNoColor().Build. 141 | WithBuildpacks(pythonBuildpack). 142 | WithPullPolicy("never"). 143 | Execute(name, filepath.Join(source, "conda")) 144 | Expect(err).NotTo(HaveOccurred()) 145 | 146 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) 147 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Conda Env Update"))) 148 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) 149 | 150 | container, err = docker.Container.Run. 151 | WithPublish("8080"). 152 | WithEnv(map[string]string{ 153 | "PORT": "8080", 154 | "SERVICE_BINDING_ROOT": "/bindings", 155 | }). 156 | WithVolumes(fmt.Sprintf("%s:/bindings/ca-certificates", filepath.Join(source, "bindings"))). 157 | Execute(image.ID) 158 | Expect(err).NotTo(HaveOccurred()) 159 | 160 | Eventually(func() string { 161 | cLogs, err := docker.Container.Logs.Execute(container.ID) 162 | Expect(err).NotTo(HaveOccurred()) 163 | return cLogs.String() 164 | }).Should( 165 | ContainSubstring("Added 1 additional CA certificate(s) to system truststore"), 166 | ) 167 | 168 | request, err := http.NewRequest("GET", fmt.Sprintf("https://localhost:%s", container.HostPort("8080")), nil) 169 | Expect(err).NotTo(HaveOccurred()) 170 | 171 | var response *http.Response 172 | Eventually(func() error { 173 | var err error 174 | response, err = client.Do(request) 175 | return err 176 | }).Should(BeNil()) 177 | defer func() { Expect(response.Body.Close()).ToNot(HaveOccurred()) }() 178 | 179 | Expect(response.StatusCode).To(Equal(http.StatusOK)) 180 | }) 181 | }) 182 | }) 183 | } 184 | -------------------------------------------------------------------------------- /.github/workflows/push-buildpackage.yml: -------------------------------------------------------------------------------- 1 | name: Push Buildpackage 2 | 3 | on: 4 | release: 5 | types: 6 | - published 7 | env: 8 | REGISTRIES_FILENAME: "registries.json" 9 | GCR_REGISTRY: "gcr.io" 10 | GCR_PASSWORD: ${{ secrets.GCR_PUSH_BOT_JSON_KEY }} 11 | GCR_USERNAME: "_json_key" 12 | DOCKERHUB_REGISTRY: docker.io 13 | DOCKERHUB_USERNAME: ${{ secrets.PAKETO_BUILDPACKS_DOCKERHUB_USERNAME }} 14 | DOCKERHUB_PASSWORD: ${{ secrets.PAKETO_BUILDPACKS_DOCKERHUB_PASSWORD }} 15 | 16 | jobs: 17 | push: 18 | name: Push 19 | runs-on: ubuntu-24.04 20 | steps: 21 | 22 | - name: Checkout 23 | uses: actions/checkout@v6 24 | 25 | - name: Parse Event 26 | id: event 27 | run: | 28 | FULL_VERSION="$(jq -r '.release.tag_name' "${GITHUB_EVENT_PATH}" | sed s/^v//)" 29 | MINOR_VERSION="$(echo "${FULL_VERSION}" | awk -F '.' '{print $1 "." $2 }')" 30 | MAJOR_VERSION="$(echo "${FULL_VERSION}" | awk -F '.' '{print $1 }')" 31 | echo "tag_full=${FULL_VERSION}" >> "$GITHUB_OUTPUT" 32 | echo "tag_minor=${MINOR_VERSION}" >> "$GITHUB_OUTPUT" 33 | echo "tag_major=${MAJOR_VERSION}" >> "$GITHUB_OUTPUT" 34 | echo "download_tgz_file_url=$(jq -r '.release.assets[] | select(.name | endswith(".tgz")) | .url' "${GITHUB_EVENT_PATH}")" >> "$GITHUB_OUTPUT" 35 | 36 | - name: Download .tgz buildpack release artifact 37 | uses: paketo-buildpacks/github-config/actions/release/download-asset@main 38 | with: 39 | url: ${{ steps.event.outputs.download_tgz_file_url }} 40 | output: "/github/workspace/buildpack-release-artifact.tgz" 41 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }} 42 | 43 | - name: Parse Configs 44 | id: parse_configs 45 | run: | 46 | registries_filename="${{ env.REGISTRIES_FILENAME }}" 47 | 48 | push_to_dockerhub=true 49 | push_to_gcr=false 50 | 51 | if [[ -f $registries_filename ]]; then 52 | if jq 'has("dockerhub")' $registries_filename > /dev/null; then 53 | push_to_dockerhub=$(jq '.dockerhub' $registries_filename) 54 | fi 55 | if jq 'has("GCR")' $registries_filename > /dev/null; then 56 | push_to_gcr=$(jq '.GCR' $registries_filename) 57 | fi 58 | fi 59 | 60 | echo "push_to_dockerhub=${push_to_dockerhub}" >> "$GITHUB_OUTPUT" 61 | echo "push_to_gcr=${push_to_gcr}" >> "$GITHUB_OUTPUT" 62 | 63 | - name: Install yj and crane 64 | uses: buildpacks/github-actions/setup-tools@v5.10.0 65 | 66 | - name: Validate version 67 | run: | 68 | buidpackTomlVersion=$(tar -xzf buildpack-release-artifact.tgz --to-stdout buildpack.toml | yj -tj | jq -r .buildpack.version) 69 | githubReleaseVersion="${{ steps.event.outputs.tag_full }}" 70 | if [[ "$buidpackTomlVersion" != "$githubReleaseVersion" ]]; then 71 | echo "Version in buildpack.toml ($buidpackTomlVersion) and github release ($githubReleaseVersion) are not identical" 72 | exit 1 73 | fi 74 | 75 | - name: Docker login docker.io 76 | uses: docker/login-action@v3 77 | with: 78 | username: ${{ env.DOCKERHUB_USERNAME }} 79 | password: ${{ env.DOCKERHUB_PASSWORD }} 80 | registry: ${{ env.DOCKERHUB_REGISTRY }} 81 | 82 | - name: Docker login gcr.io 83 | uses: docker/login-action@v3 84 | if: ${{ steps.parse_configs.outputs.push_to_gcr == 'true' }} 85 | with: 86 | username: ${{ env.GCR_USERNAME }} 87 | password: ${{ env.GCR_PASSWORD }} 88 | registry: ${{ env.GCR_REGISTRY }} 89 | 90 | - name: Push to GCR 91 | if: ${{ steps.parse_configs.outputs.push_to_gcr == 'true' }} 92 | run: | 93 | ./scripts/publish.sh \ 94 | --archive-path buildpack-release-artifact.tgz \ 95 | --image-ref "gcr.io/${{ github.repository }}:${{ steps.event.outputs.tag_full }}" 96 | 97 | crane copy "gcr.io/${{ github.repository }}:${{ steps.event.outputs.tag_full }}" "gcr.io/${{ github.repository }}:${{ steps.event.outputs.tag_minor }}" 98 | crane copy "gcr.io/${{ github.repository }}:${{ steps.event.outputs.tag_full }}" "gcr.io/${{ github.repository }}:${{ steps.event.outputs.tag_major }}" 99 | crane copy "gcr.io/${{ github.repository }}:${{ steps.event.outputs.tag_full }}" "gcr.io/${{ github.repository }}:latest" 100 | 101 | - name: Push to DockerHub 102 | if: ${{ steps.parse_configs.outputs.push_to_dockerhub == 'true' }} 103 | id: push 104 | run: | 105 | IMAGE="${GITHUB_REPOSITORY_OWNER/-/}/${GITHUB_REPOSITORY#${GITHUB_REPOSITORY_OWNER}/}" # translates 'paketo-buildpacks/bundle-install' to 'paketobuildpacks/bundle-install' 106 | 107 | ./scripts/publish.sh \ 108 | --archive-path buildpack-release-artifact.tgz \ 109 | --image-ref "${DOCKERHUB_REGISTRY}/${IMAGE}:${{ steps.event.outputs.tag_full }}" 110 | 111 | pushed_image_index_digest=$(crane digest "${DOCKERHUB_REGISTRY}/${IMAGE}:${{ steps.event.outputs.tag_full }}" | xargs) 112 | 113 | crane copy "${DOCKERHUB_REGISTRY}/${IMAGE}:${{ steps.event.outputs.tag_full }}" "${DOCKERHUB_REGISTRY}/${IMAGE}:${{ steps.event.outputs.tag_minor }}" 114 | crane copy "${DOCKERHUB_REGISTRY}/${IMAGE}:${{ steps.event.outputs.tag_full }}" "${DOCKERHUB_REGISTRY}/${IMAGE}:${{ steps.event.outputs.tag_major }}" 115 | crane copy "${DOCKERHUB_REGISTRY}/${IMAGE}:${{ steps.event.outputs.tag_full }}" "${DOCKERHUB_REGISTRY}/${IMAGE}:latest" 116 | 117 | echo "image=${IMAGE}" >> "$GITHUB_OUTPUT" 118 | echo "digest=$pushed_image_index_digest" >> "$GITHUB_OUTPUT" 119 | 120 | - name: Register with CNB Registry 121 | uses: docker://ghcr.io/buildpacks/actions/registry/request-add-entry:main 122 | with: 123 | id: ${{ github.repository }} 124 | version: ${{ steps.event.outputs.tag_full }} 125 | address: index.docker.io/${{ steps.push.outputs.image }}@${{ steps.push.outputs.digest }} 126 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }} 127 | 128 | failure: 129 | name: Alert on Failure 130 | runs-on: ubuntu-24.04 131 | needs: [push] 132 | if: ${{ always() && needs.push.result == 'failure' }} 133 | steps: 134 | - name: File Failure Alert Issue 135 | uses: paketo-buildpacks/github-config/actions/issue/file@main 136 | with: 137 | token: ${{ secrets.GITHUB_TOKEN }} 138 | repo: ${{ github.repository }} 139 | label: "failure:push" 140 | comment_if_exists: true 141 | issue_title: "Failure: Push Buildpackage workflow" 142 | issue_body: | 143 | Push Buildpackage workflow [failed](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}). 144 | comment_body: | 145 | Another failure occurred: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} 146 | -------------------------------------------------------------------------------- /integration/pip_test.go: -------------------------------------------------------------------------------- 1 | package integration_test 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | "fmt" 7 | "io" 8 | "net/http" 9 | "os" 10 | "path/filepath" 11 | "testing" 12 | 13 | "github.com/paketo-buildpacks/occam" 14 | "github.com/sclevine/spec" 15 | 16 | . "github.com/onsi/gomega" 17 | . "github.com/paketo-buildpacks/occam/matchers" 18 | ) 19 | 20 | func testPip(t *testing.T, context spec.G, it spec.S) { 21 | var ( 22 | Expect = NewWithT(t).Expect 23 | Eventually = NewWithT(t).Eventually 24 | 25 | pack occam.Pack 26 | docker occam.Docker 27 | ) 28 | 29 | it.Before(func() { 30 | pack = occam.NewPack() 31 | docker = occam.NewDocker() 32 | }) 33 | 34 | context("when building a pip app", func() { 35 | var ( 36 | image occam.Image 37 | container occam.Container 38 | 39 | name string 40 | source string 41 | ) 42 | 43 | it.Before(func() { 44 | var err error 45 | name, err = occam.RandomName() 46 | Expect(err).NotTo(HaveOccurred()) 47 | }) 48 | 49 | it.After(func() { 50 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed()) 51 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed()) 52 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed()) 53 | Expect(os.RemoveAll(source)).To(Succeed()) 54 | }) 55 | 56 | it("creates a working OCI image with a start command", func() { 57 | var err error 58 | source, err = occam.Source(filepath.Join("testdata", "pip")) 59 | Expect(err).NotTo(HaveOccurred()) 60 | 61 | var logs fmt.Stringer 62 | image, logs, err = pack.WithNoColor().Build. 63 | WithBuildpacks(pythonBuildpack). 64 | WithPullPolicy("never"). 65 | WithEnv(map[string]string{ 66 | "BPE_SOME_VARIABLE": "some-value", 67 | "BP_IMAGE_LABELS": "some-label=some-value", 68 | "BP_LIVE_RELOAD_ENABLED": "true", 69 | }). 70 | Execute(name, source) 71 | Expect(err).NotTo(HaveOccurred(), logs.String()) 72 | 73 | container, err = docker.Container.Run. 74 | WithEnv(map[string]string{"PORT": "8080"}). 75 | WithPublish("8080"). 76 | WithPublishAll(). 77 | Execute(image.ID) 78 | Expect(err).NotTo(HaveOccurred()) 79 | 80 | Eventually(container).Should(BeAvailable()) 81 | 82 | response, err := http.Get(fmt.Sprintf("http://localhost:%s", container.HostPort("8080"))) 83 | Expect(err).NotTo(HaveOccurred()) 84 | defer func() { Expect(response.Body.Close()).ToNot(HaveOccurred()) }() 85 | 86 | Expect(response.StatusCode).To(Equal(http.StatusOK)) 87 | 88 | content, err := io.ReadAll(response.Body) 89 | Expect(err).NotTo(HaveOccurred()) 90 | Expect(string(content)).To(ContainSubstring("Hello, World with pip!")) 91 | 92 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) 93 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CPython"))) 94 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pip"))) 95 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pip Install"))) 96 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) 97 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Procfile"))) 98 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Environment Variables"))) 99 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Image Labels"))) 100 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Watchexec"))) 101 | 102 | Expect(image.Buildpacks[7].Key).To(Equal("paketo-buildpacks/environment-variables")) 103 | Expect(image.Buildpacks[7].Layers["environment-variables"].Metadata["variables"]).To(Equal(map[string]interface{}{"SOME_VARIABLE": "some-value"})) 104 | Expect(image.Labels["some-label"]).To(Equal("some-value")) 105 | }) 106 | 107 | context("when using CA certificates", func() { 108 | var client *http.Client 109 | 110 | it.Before(func() { 111 | var err error 112 | source, err = occam.Source(filepath.Join("testdata", "ca_cert_apps")) 113 | Expect(err).NotTo(HaveOccurred()) 114 | 115 | caCert, err := os.ReadFile(filepath.Join(source, "client_certs", "ca.pem")) 116 | Expect(err).NotTo(HaveOccurred()) 117 | 118 | caCertPool := x509.NewCertPool() 119 | caCertPool.AppendCertsFromPEM(caCert) 120 | 121 | cert, err := tls.LoadX509KeyPair( 122 | filepath.Join(source, "client_certs", "cert.pem"), 123 | filepath.Join(source, "client_certs", "key.pem")) 124 | Expect(err).NotTo(HaveOccurred()) 125 | 126 | client = &http.Client{ 127 | Transport: &http.Transport{ 128 | TLSClientConfig: &tls.Config{ 129 | RootCAs: caCertPool, 130 | Certificates: []tls.Certificate{cert}, 131 | MinVersion: tls.VersionTLS12, 132 | }, 133 | }, 134 | } 135 | }) 136 | 137 | it("builds a working OCI image with a start command and uses a client-side CA cert for requests", func() { 138 | var err error 139 | var logs fmt.Stringer 140 | 141 | image, logs, err = pack.WithNoColor().Build. 142 | WithBuildpacks(pythonBuildpack). 143 | WithPullPolicy("never"). 144 | Execute(name, filepath.Join(source, "pip")) 145 | Expect(err).NotTo(HaveOccurred()) 146 | 147 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) 148 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CPython"))) 149 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pip"))) 150 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pip Install"))) 151 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) 152 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Procfile"))) 153 | 154 | container, err = docker.Container.Run. 155 | WithPublish("8080"). 156 | WithEnv(map[string]string{ 157 | "PORT": "8080", 158 | "SERVICE_BINDING_ROOT": "/bindings", 159 | }). 160 | WithVolumes(fmt.Sprintf("%s:/bindings/ca-certificates", filepath.Join(source, "bindings"))). 161 | Execute(image.ID) 162 | Expect(err).NotTo(HaveOccurred()) 163 | 164 | Eventually(func() string { 165 | cLogs, err := docker.Container.Logs.Execute(container.ID) 166 | Expect(err).NotTo(HaveOccurred()) 167 | return cLogs.String() 168 | }).Should( 169 | ContainSubstring("Added 1 additional CA certificate(s) to system truststore"), 170 | ) 171 | 172 | request, err := http.NewRequest("GET", fmt.Sprintf("https://localhost:%s", container.HostPort("8080")), nil) 173 | Expect(err).NotTo(HaveOccurred()) 174 | 175 | var response *http.Response 176 | Eventually(func() error { 177 | var err error 178 | response, err = client.Do(request) 179 | return err 180 | }).Should(BeNil()) 181 | defer func() { Expect(response.Body.Close()).ToNot(HaveOccurred()) }() 182 | 183 | Expect(response.StatusCode).To(Equal(http.StatusOK)) 184 | }) 185 | }) 186 | }) 187 | } 188 | -------------------------------------------------------------------------------- /integration/pipenv_test.go: -------------------------------------------------------------------------------- 1 | package integration_test 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | "fmt" 7 | "io" 8 | "net/http" 9 | "os" 10 | "path/filepath" 11 | "testing" 12 | 13 | "github.com/paketo-buildpacks/occam" 14 | "github.com/sclevine/spec" 15 | 16 | . "github.com/onsi/gomega" 17 | . "github.com/paketo-buildpacks/occam/matchers" 18 | ) 19 | 20 | func testPipenv(t *testing.T, context spec.G, it spec.S) { 21 | var ( 22 | Expect = NewWithT(t).Expect 23 | Eventually = NewWithT(t).Eventually 24 | 25 | pack occam.Pack 26 | docker occam.Docker 27 | ) 28 | 29 | it.Before(func() { 30 | pack = occam.NewPack() 31 | docker = occam.NewDocker() 32 | }) 33 | 34 | context("when building a pipenv app", func() { 35 | var ( 36 | image occam.Image 37 | container occam.Container 38 | 39 | name string 40 | source string 41 | ) 42 | 43 | it.Before(func() { 44 | var err error 45 | name, err = occam.RandomName() 46 | Expect(err).NotTo(HaveOccurred()) 47 | }) 48 | 49 | it.After(func() { 50 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed()) 51 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed()) 52 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed()) 53 | Expect(os.RemoveAll(source)).To(Succeed()) 54 | }) 55 | 56 | it("creates a working OCI image with a start command", func() { 57 | var err error 58 | source, err = occam.Source(filepath.Join("testdata", "pipenv")) 59 | Expect(err).NotTo(HaveOccurred()) 60 | 61 | var logs fmt.Stringer 62 | image, logs, err = pack.WithNoColor().Build. 63 | WithBuildpacks(pythonBuildpack). 64 | WithPullPolicy("never"). 65 | WithEnv(map[string]string{ 66 | "BPE_SOME_VARIABLE": "some-value", 67 | "BP_IMAGE_LABELS": "some-label=some-value", 68 | "BP_LIVE_RELOAD_ENABLED": "true", 69 | }). 70 | Execute(name, source) 71 | Expect(err).NotTo(HaveOccurred(), logs.String()) 72 | 73 | container, err = docker.Container.Run. 74 | WithEnv(map[string]string{"PORT": "8080"}). 75 | WithPublish("8080"). 76 | WithPublishAll(). 77 | Execute(image.ID) 78 | Expect(err).NotTo(HaveOccurred()) 79 | 80 | Eventually(container).Should(BeAvailable()) 81 | 82 | response, err := http.Get(fmt.Sprintf("http://localhost:%s", container.HostPort("8080"))) 83 | Expect(err).NotTo(HaveOccurred()) 84 | defer func() { Expect(response.Body.Close()).ToNot(HaveOccurred()) }() 85 | 86 | Expect(response.StatusCode).To(Equal(http.StatusOK)) 87 | 88 | content, err := io.ReadAll(response.Body) 89 | Expect(err).NotTo(HaveOccurred()) 90 | Expect(string(content)).To(ContainSubstring("Hello, World with pipenv!")) 91 | 92 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) 93 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CPython"))) 94 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pip"))) 95 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pipenv"))) 96 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pipenv Install"))) 97 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) 98 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Procfile"))) 99 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Environment Variables"))) 100 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Image Labels"))) 101 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Watchexec"))) 102 | 103 | Expect(image.Buildpacks[8].Key).To(Equal("paketo-buildpacks/environment-variables")) 104 | Expect(image.Buildpacks[8].Layers["environment-variables"].Metadata["variables"]).To(Equal(map[string]interface{}{"SOME_VARIABLE": "some-value"})) 105 | Expect(image.Labels["some-label"]).To(Equal("some-value")) 106 | }) 107 | 108 | context("when using CA certificates", func() { 109 | var client *http.Client 110 | 111 | it.Before(func() { 112 | var err error 113 | source, err = occam.Source(filepath.Join("testdata", "ca_cert_apps")) 114 | Expect(err).NotTo(HaveOccurred()) 115 | 116 | caCert, err := os.ReadFile(filepath.Join(source, "client_certs", "ca.pem")) 117 | Expect(err).NotTo(HaveOccurred()) 118 | 119 | caCertPool := x509.NewCertPool() 120 | caCertPool.AppendCertsFromPEM(caCert) 121 | 122 | cert, err := tls.LoadX509KeyPair( 123 | filepath.Join(source, "client_certs", "cert.pem"), 124 | filepath.Join(source, "client_certs", "key.pem")) 125 | Expect(err).NotTo(HaveOccurred()) 126 | 127 | client = &http.Client{ 128 | Transport: &http.Transport{ 129 | TLSClientConfig: &tls.Config{ 130 | RootCAs: caCertPool, 131 | Certificates: []tls.Certificate{cert}, 132 | MinVersion: tls.VersionTLS12, 133 | }, 134 | }, 135 | } 136 | }) 137 | 138 | it("builds a working OCI image with a start command and uses a client-side CA cert for requests", func() { 139 | var err error 140 | var logs fmt.Stringer 141 | 142 | image, logs, err = pack.WithNoColor().Build. 143 | WithBuildpacks(pythonBuildpack). 144 | WithPullPolicy("never"). 145 | Execute(name, filepath.Join(source, "pipenv")) 146 | Expect(err).NotTo(HaveOccurred()) 147 | 148 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) 149 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CPython"))) 150 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pip"))) 151 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pipenv"))) 152 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pipenv Install"))) 153 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) 154 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Procfile"))) 155 | 156 | container, err = docker.Container.Run. 157 | WithPublish("8080"). 158 | WithEnv(map[string]string{ 159 | "PORT": "8080", 160 | "SERVICE_BINDING_ROOT": "/bindings", 161 | }). 162 | WithVolumes(fmt.Sprintf("%s:/bindings/ca-certificates", filepath.Join(source, "bindings"))). 163 | Execute(image.ID) 164 | Expect(err).NotTo(HaveOccurred()) 165 | 166 | Eventually(func() string { 167 | cLogs, err := docker.Container.Logs.Execute(container.ID) 168 | Expect(err).NotTo(HaveOccurred()) 169 | return cLogs.String() 170 | }).Should( 171 | ContainSubstring("Added 1 additional CA certificate(s) to system truststore"), 172 | ) 173 | 174 | request, err := http.NewRequest("GET", fmt.Sprintf("https://localhost:%s", container.HostPort("8080")), nil) 175 | Expect(err).NotTo(HaveOccurred()) 176 | 177 | var response *http.Response 178 | Eventually(func() error { 179 | var err error 180 | response, err = client.Do(request) 181 | return err 182 | }).Should(BeNil()) 183 | defer func() { Expect(response.Body.Close()).ToNot(HaveOccurred()) }() 184 | 185 | Expect(response.StatusCode).To(Equal(http.StatusOK)) 186 | }) 187 | }) 188 | }) 189 | } 190 | -------------------------------------------------------------------------------- /scripts/package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | readonly ROOT_DIR="$(cd "$(dirname "${0}")/.." && pwd)" 8 | readonly BIN_DIR="${ROOT_DIR}/.bin" 9 | readonly BUILD_DIR="${ROOT_DIR}/build" 10 | 11 | # shellcheck source=SCRIPTDIR/.util/tools.sh 12 | source "${ROOT_DIR}/scripts/.util/tools.sh" 13 | 14 | # shellcheck source=SCRIPTDIR/.util/print.sh 15 | source "${ROOT_DIR}/scripts/.util/print.sh" 16 | 17 | function main { 18 | local version output token flags 19 | token="" 20 | 21 | while [[ "${#}" != 0 ]]; do 22 | case "${1}" in 23 | --version|-v) 24 | version="${2}" 25 | shift 2 26 | ;; 27 | 28 | --output|-o) 29 | output="${2}" 30 | shift 2 31 | ;; 32 | 33 | --token|-t) 34 | token="${2}" 35 | shift 2 36 | ;; 37 | 38 | --label) 39 | flags+=("--label" "${2}") 40 | shift 2 41 | ;; 42 | 43 | --help|-h) 44 | shift 1 45 | usage 46 | exit 0 47 | ;; 48 | 49 | "") 50 | # skip if the argument is empty 51 | shift 1 52 | ;; 53 | 54 | *) 55 | util::print::error "unknown argument \"${1}\"" 56 | esac 57 | done 58 | 59 | if [[ -z "${version:-}" ]]; then 60 | usage 61 | echo 62 | util::print::error "--version is required" 63 | fi 64 | 65 | if [[ -z "${output:-}" ]]; then 66 | output="${BUILD_DIR}/buildpackage.cnb" 67 | fi 68 | 69 | repo::prepare 70 | 71 | tools::install "${token}" 72 | 73 | buildpack::archive "${version}" 74 | buildpack::release::archive 75 | buildpackage::create "${output}" "${flags[@]}" 76 | } 77 | 78 | function usage() { 79 | cat <<-USAGE 80 | package.sh --version [OPTIONS] 81 | 82 | Packages the buildpack into a buildpackage .cnb file. 83 | 84 | OPTIONS 85 | --help -h prints the command usage 86 | --version -v specifies the version number to use when packaging the buildpack 87 | --output -o location to output the packaged buildpackage artifact (default: ${ROOT_DIR}/build/buildpackage.cnb) 88 | --token Token used to download assets from GitHub (e.g. jam, pack, etc) (optional) 89 | USAGE 90 | } 91 | 92 | function repo::prepare() { 93 | util::print::title "Preparing repo..." 94 | 95 | rm -rf "${BUILD_DIR}" 96 | 97 | mkdir -p "${BIN_DIR}" 98 | mkdir -p "${BUILD_DIR}" 99 | 100 | export PATH="${BIN_DIR}:${PATH}" 101 | } 102 | 103 | function tools::install() { 104 | local token 105 | token="${1}" 106 | 107 | util::tools::jam::install \ 108 | --directory "${BIN_DIR}" \ 109 | --token "${token}" 110 | 111 | util::tools::pack::install \ 112 | --directory "${BIN_DIR}" \ 113 | --token "${token}" 114 | 115 | util::tools::yj::install \ 116 | --directory "${BIN_DIR}" \ 117 | --token "${token}" 118 | } 119 | 120 | function buildpack::archive() { 121 | local version 122 | version="${1}" 123 | 124 | util::print::title "Packaging buildpack into ${BUILD_DIR}/buildpack.tgz..." 125 | 126 | jam pack \ 127 | --buildpack "${ROOT_DIR}/buildpack.toml" \ 128 | --version "${version}" \ 129 | --offline \ 130 | --output "${BUILD_DIR}/buildpack.tgz" 131 | } 132 | 133 | function buildpack::release::archive() { 134 | local tmp_dir 135 | 136 | util::print::title "Packaging buildpack into ${BUILD_DIR}/buildpack-release-artifact.tgz..." 137 | 138 | tmp_dir=$(mktemp -d -p $BUILD_DIR) 139 | 140 | cat <<'README_EOF' > $tmp_dir/README.md 141 | # Composite buildpack release artifact 142 | 143 | This is a buildpack release artifact that contains everything needed to package and publish a composite buildpack. Composite buildpacks are a logic grouping of other buildpacks. 144 | 145 | It contains the following files: 146 | 147 | * `buildpack.toml` - this is needed because it contains the buildpacks and ordering information for the composite buildpack 148 | * `package.toml` - this is needed because it contains the dependencies (and URIs) that let pack know where to find the buildpacks referenced in `buildpack.toml`. 149 | * `package.toml` can contain targets (platforms) for multi-arch support 150 | * `build/buildpack.tgz` - this is added because it is referenced in `package.toml` by some buildpacks 151 | 152 | ## package locally 153 | 154 | To package this buildpack to local .cnb file(s) run the following. 155 | 156 | ``` 157 | pack buildpack package mybuildpack.cnb --format file --config package.toml 158 | ``` 159 | 160 | ## package and publish to a registry 161 | 162 | To package this buildpack and publish it to a registry run the following. 163 | 164 | * Note that as of pack v0.38.2 at least one target is required in package.toml or on the command line when publishing to a registry with `--publish`. 165 | 166 | * replace SOME-REGISTRY with your registry (e.g. index.docker.io/yourdockerhubusername) 167 | * replace SOME-VERSION with the version you want to publish (e.g. 0.0.1) 168 | 169 | ``` 170 | pack buildpack package SOME-REGISTRY/mybuildpack:SOME-VERSION --format image --config package.toml --publish 171 | ``` 172 | README_EOF 173 | 174 | mkdir -p $tmp_dir/build 175 | cp ${BUILD_DIR}/buildpack.tgz $tmp_dir/build 176 | cp ${ROOT_DIR}/package.toml $tmp_dir/ 177 | # add the buildpack.toml from the tgz file because it has the version populated 178 | tar -xzf ${BUILD_DIR}/buildpack.tgz -C $tmp_dir/ buildpack.toml 179 | 180 | tar -czf ${BUILD_DIR}/buildpack-release-artifact.tgz -C $tmp_dir $(ls $tmp_dir) 181 | rm -rf $tmp_dir 182 | } 183 | 184 | function buildpackage::create() { 185 | local output flags release_archive_path tmp_dir 186 | output="${1}" 187 | flags=("${@:2}") 188 | release_archive_path="${BUILD_DIR}/buildpack-release-artifact.tgz" 189 | 190 | util::print::title "Packaging buildpack..." 191 | 192 | util::print::info "Extracting release archive..." 193 | tmp_dir=$(mktemp -d -p $BUILD_DIR) 194 | tar -xvf $release_archive_path -C $tmp_dir 195 | 196 | current_dir=$(pwd) 197 | cd $tmp_dir 198 | 199 | args=( 200 | --config package.toml 201 | --format file 202 | ) 203 | 204 | args+=("${flags[@]}") 205 | 206 | # Use the local architecture to support running locally and in CI, which will be linux/amd64 by default. 207 | arch=$(util::tools::arch) 208 | 209 | # If package.toml has no targets we must specify one on the command line, otherwise pack will complain. 210 | # This is here for backward compatibility but eventually all package.toml files should have targets defined. 211 | if cat package.toml | yj -tj | jq -r .targets | grep -q null; then 212 | echo "package.toml has no targets so --target linux/${arch} will be passed to pack" 213 | args+=("--target linux/${arch}") 214 | fi 215 | 216 | pack \ 217 | buildpack package "${output}" \ 218 | ${args[@]} 219 | 220 | if [[ -e "${BUILD_DIR}/buildpackage-linux-${arch}.cnb" ]]; then 221 | echo "Copying linux-${arch} buildpackage to buildpackage.cnb" 222 | cp "${BUILD_DIR}/buildpackage-linux-${arch}.cnb" "${BUILD_DIR}/buildpackage.cnb" 223 | fi 224 | 225 | cd $current_dir 226 | rm -rf $tmp_dir 227 | } 228 | 229 | main "${@:-}" 230 | -------------------------------------------------------------------------------- /integration/no_package_manager_test.go: -------------------------------------------------------------------------------- 1 | package integration_test 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | "fmt" 7 | "net/http" 8 | "os" 9 | "path/filepath" 10 | "testing" 11 | 12 | "github.com/paketo-buildpacks/occam" 13 | "github.com/sclevine/spec" 14 | 15 | . "github.com/onsi/gomega" 16 | . "github.com/paketo-buildpacks/occam/matchers" 17 | ) 18 | 19 | func testNoPackageManager(t *testing.T, context spec.G, it spec.S) { 20 | var ( 21 | Expect = NewWithT(t).Expect 22 | Eventually = NewWithT(t).Eventually 23 | 24 | pack occam.Pack 25 | docker occam.Docker 26 | ) 27 | 28 | it.Before(func() { 29 | pack = occam.NewPack() 30 | docker = occam.NewDocker() 31 | }) 32 | 33 | context("when building an app with no package manager", func() { 34 | var ( 35 | image occam.Image 36 | container occam.Container 37 | 38 | name string 39 | source string 40 | ) 41 | 42 | it.Before(func() { 43 | var err error 44 | name, err = occam.RandomName() 45 | Expect(err).NotTo(HaveOccurred()) 46 | }) 47 | 48 | it.After(func() { 49 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed()) 50 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed()) 51 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed()) 52 | Expect(os.RemoveAll(source)).To(Succeed()) 53 | }) 54 | 55 | it("creates a working OCI image with a start command", func() { 56 | var err error 57 | source, err = occam.Source(filepath.Join("testdata", "no_package_manager")) 58 | Expect(err).NotTo(HaveOccurred()) 59 | 60 | var logs fmt.Stringer 61 | image, logs, err = pack.WithNoColor().Build. 62 | WithBuildpacks(pythonBuildpack). 63 | WithPullPolicy("never"). 64 | Execute(name, source) 65 | Expect(err).NotTo(HaveOccurred(), logs.String()) 66 | 67 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CPython"))) 68 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) 69 | 70 | container, err = docker.Container.Run. 71 | WithCommand("hello.py"). 72 | Execute(image.ID) 73 | Expect(err).NotTo(HaveOccurred()) 74 | 75 | Eventually(func() string { 76 | cLogs, err := docker.Container.Logs.Execute(container.ID) 77 | Expect(err).NotTo(HaveOccurred()) 78 | return cLogs.String() 79 | }).Should(ContainSubstring("Hello")) 80 | }) 81 | 82 | context("when using optional utility buildpacks", func() { 83 | it("creates a working OCI image that starts the right process and uses other utility buildpacks", func() { 84 | var err error 85 | source, err = occam.Source(filepath.Join("testdata", "no_package_manager")) 86 | Expect(err).NotTo(HaveOccurred()) 87 | 88 | Expect(os.WriteFile(filepath.Join(source, "Procfile"), 89 | []byte("web: python hello.py"), os.ModePerm)). 90 | To(Succeed()) 91 | 92 | var logs fmt.Stringer 93 | image, logs, err = pack.WithNoColor().Build. 94 | WithBuildpacks(pythonBuildpack). 95 | WithPullPolicy("never"). 96 | WithEnv(map[string]string{ 97 | "BPE_SOME_VARIABLE": "some-value", 98 | "BP_IMAGE_LABELS": "some-label=some-value", 99 | "BP_LIVE_RELOAD_ENABLED": "true", 100 | }). 101 | Execute(name, source) 102 | Expect(err).NotTo(HaveOccurred(), logs.String()) 103 | 104 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) 105 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CPython"))) 106 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) 107 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Procfile"))) 108 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Environment Variables"))) 109 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Image Labels"))) 110 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Watchexec"))) 111 | 112 | Expect(image.Buildpacks[5].Key).To(Equal("paketo-buildpacks/environment-variables")) 113 | Expect(image.Buildpacks[5].Layers["environment-variables"].Metadata["variables"]).To(Equal(map[string]interface{}{"SOME_VARIABLE": "some-value"})) 114 | Expect(image.Labels["some-label"]).To(Equal("some-value")) 115 | 116 | container, err = docker.Container.Run.Execute(image.ID) 117 | Expect(err).NotTo(HaveOccurred()) 118 | 119 | Eventually(func() string { 120 | cLogs, err := docker.Container.Logs.Execute(container.ID) 121 | Expect(err).NotTo(HaveOccurred()) 122 | return cLogs.String() 123 | }).Should(ContainSubstring("Hello")) 124 | }) 125 | }) 126 | 127 | context("when using CA certificates", func() { 128 | var client *http.Client 129 | 130 | it.Before(func() { 131 | var err error 132 | source, err = occam.Source(filepath.Join("testdata", "ca_cert_apps")) 133 | Expect(err).NotTo(HaveOccurred()) 134 | 135 | caCert, err := os.ReadFile(filepath.Join(source, "client_certs", "ca.pem")) 136 | Expect(err).NotTo(HaveOccurred()) 137 | 138 | caCertPool := x509.NewCertPool() 139 | caCertPool.AppendCertsFromPEM(caCert) 140 | 141 | cert, err := tls.LoadX509KeyPair( 142 | filepath.Join(source, "client_certs", "cert.pem"), 143 | filepath.Join(source, "client_certs", "key.pem")) 144 | Expect(err).NotTo(HaveOccurred()) 145 | 146 | client = &http.Client{ 147 | Transport: &http.Transport{ 148 | TLSClientConfig: &tls.Config{ 149 | RootCAs: caCertPool, 150 | Certificates: []tls.Certificate{cert}, 151 | MinVersion: tls.VersionTLS12, 152 | }, 153 | }, 154 | } 155 | }) 156 | 157 | it("builds a working OCI image with a start command and uses a client-side CA cert for requests", func() { 158 | var err error 159 | var logs fmt.Stringer 160 | 161 | image, logs, err = pack.WithNoColor().Build. 162 | WithBuildpacks(pythonBuildpack). 163 | WithPullPolicy("never"). 164 | Execute(name, filepath.Join(source, "no_package_manager")) 165 | Expect(err).NotTo(HaveOccurred()) 166 | 167 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) 168 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CPython"))) 169 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) 170 | Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Procfile"))) 171 | 172 | container, err = docker.Container.Run. 173 | WithPublish("8080"). 174 | WithEnv(map[string]string{ 175 | "PORT": "8080", 176 | "SERVICE_BINDING_ROOT": "/bindings", 177 | }). 178 | WithVolumes(fmt.Sprintf("%s:/bindings/ca-certificates", filepath.Join(source, "bindings"))). 179 | Execute(image.ID) 180 | Expect(err).NotTo(HaveOccurred()) 181 | 182 | Eventually(func() string { 183 | cLogs, err := docker.Container.Logs.Execute(container.ID) 184 | Expect(err).NotTo(HaveOccurred()) 185 | return cLogs.String() 186 | }).Should( 187 | ContainSubstring("Added 1 additional CA certificate(s) to system truststore"), 188 | ) 189 | 190 | request, err := http.NewRequest("GET", fmt.Sprintf("https://localhost:%s", container.HostPort("8080")), nil) 191 | Expect(err).NotTo(HaveOccurred()) 192 | 193 | var response *http.Response 194 | Eventually(func() error { 195 | var err error 196 | response, err = client.Do(request) 197 | return err 198 | }).Should(BeNil()) 199 | defer func() { Expect(response.Body.Close()).ToNot(HaveOccurred()) }() 200 | 201 | Expect(response.StatusCode).To(Equal(http.StatusOK)) 202 | }) 203 | }) 204 | }) 205 | } 206 | -------------------------------------------------------------------------------- /scripts/.util/tools.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | set -o pipefail 5 | 6 | # shellcheck source=SCRIPTDIR/print.sh 7 | source "$(dirname "${BASH_SOURCE[0]}")/print.sh" 8 | 9 | function util::tools::os() { 10 | case "$(uname)" in 11 | "Darwin") 12 | echo "${1:-darwin}" 13 | ;; 14 | 15 | "Linux") 16 | echo "linux" 17 | ;; 18 | 19 | *) 20 | util::print::error "Unknown OS \"$(uname)\"" 21 | exit 1 22 | esac 23 | } 24 | 25 | function util::tools::arch() { 26 | case "$(uname -m)" in 27 | arm64|aarch64) 28 | echo "arm64" 29 | ;; 30 | 31 | amd64|x86_64) 32 | if [[ "${1:-}" == "--blank-amd64" ]]; then 33 | echo "" 34 | elif [[ "${1:-}" == "--format-amd64-x86_64" ]]; then 35 | echo "x86_64" 36 | elif [[ "${1:-}" == "--format-amd64-x86-64" ]]; then 37 | echo "x86-64" 38 | else 39 | echo "amd64" 40 | fi 41 | ;; 42 | 43 | *) 44 | util::print::error "Unknown Architecture \"$(uname -m)\"" 45 | exit 1 46 | esac 47 | } 48 | 49 | function util::tools::path::export() { 50 | local dir 51 | dir="${1}" 52 | 53 | if ! echo "${PATH}" | grep -q "${dir}"; then 54 | PATH="${dir}:$PATH" 55 | export PATH 56 | fi 57 | } 58 | 59 | function util::tools::jam::install() { 60 | local dir token 61 | token="" 62 | 63 | while [[ "${#}" != 0 ]]; do 64 | case "${1}" in 65 | --directory) 66 | dir="${2}" 67 | shift 2 68 | ;; 69 | 70 | --token) 71 | token="${2}" 72 | shift 2 73 | ;; 74 | 75 | *) 76 | util::print::error "unknown argument \"${1}\"" 77 | esac 78 | done 79 | 80 | mkdir -p "${dir}" 81 | util::tools::path::export "${dir}" 82 | 83 | if [[ ! -f "${dir}/jam" ]]; then 84 | local version curl_args os arch 85 | 86 | version="$(jq -r .jam "$(dirname "${BASH_SOURCE[0]}")/tools.json")" 87 | 88 | curl_args=( 89 | "--fail" 90 | "--silent" 91 | "--location" 92 | "--output" "${dir}/jam" 93 | ) 94 | 95 | if [[ "${token}" != "" ]]; then 96 | curl_args+=("--header" "Authorization: Token ${token}") 97 | fi 98 | 99 | util::print::title "Installing jam ${version}" 100 | 101 | os=$(util::tools::os) 102 | arch=$(util::tools::arch) 103 | 104 | curl "https://github.com/paketo-buildpacks/jam/releases/download/${version}/jam-${os}-${arch}" \ 105 | "${curl_args[@]}" 106 | 107 | chmod +x "${dir}/jam" 108 | else 109 | util::print::info "Using $("${dir}"/jam version)" 110 | fi 111 | } 112 | 113 | function util::tools::pack::install() { 114 | local dir token 115 | token="" 116 | 117 | while [[ "${#}" != 0 ]]; do 118 | case "${1}" in 119 | --directory) 120 | dir="${2}" 121 | shift 2 122 | ;; 123 | 124 | --token) 125 | token="${2}" 126 | shift 2 127 | ;; 128 | 129 | *) 130 | util::print::error "unknown argument \"${1}\"" 131 | esac 132 | done 133 | 134 | mkdir -p "${dir}" 135 | util::tools::path::export "${dir}" 136 | 137 | if [[ ! -f "${dir}/pack" ]]; then 138 | local version curl_args os arch 139 | 140 | version="$(jq -r .pack "$(dirname "${BASH_SOURCE[0]}")/tools.json")" 141 | 142 | local pack_config_enable_experimental 143 | if [ -f "$(dirname "${BASH_SOURCE[0]}")/../options.json" ]; then 144 | pack_config_enable_experimental="$(jq -r .pack_config_enable_experimental "$(dirname "${BASH_SOURCE[0]}")/../options.json")" 145 | else 146 | pack_config_enable_experimental="false" 147 | fi 148 | 149 | curl_args=( 150 | "--fail" 151 | "--silent" 152 | "--location" 153 | ) 154 | 155 | if [[ "${token}" != "" ]]; then 156 | curl_args+=("--header" "Authorization: Token ${token}") 157 | fi 158 | 159 | util::print::title "Installing pack ${version}" 160 | 161 | os=$(util::tools::os) 162 | arch=$(util::tools::arch --blank-amd64) 163 | 164 | curl "https://github.com/buildpacks/pack/releases/download/${version}/pack-${version}-${os}${arch:+-$arch}.tgz" \ 165 | "${curl_args[@]}" | \ 166 | tar xzf - -C "${dir}" 167 | chmod +x "${dir}/pack" 168 | 169 | if [[ "${pack_config_enable_experimental}" == "true" ]]; then 170 | "${dir}"/pack config experimental true 171 | fi 172 | 173 | else 174 | util::print::info "Using pack $("${dir}"/pack version)" 175 | fi 176 | } 177 | 178 | function util::tools::yj::install() { 179 | local dir token 180 | token="" 181 | 182 | while [[ "${#}" != 0 ]]; do 183 | case "${1}" in 184 | --directory) 185 | dir="${2}" 186 | shift 2 187 | ;; 188 | 189 | --token) 190 | token="${2}" 191 | shift 2 192 | ;; 193 | 194 | *) 195 | util::print::error "unknown argument \"${1}\"" 196 | esac 197 | done 198 | 199 | mkdir -p "${dir}" 200 | util::tools::path::export "${dir}" 201 | 202 | if [[ ! -f "${dir}/yj" ]]; then 203 | local version curl_args os arch 204 | 205 | version="$(jq -r .yj "$(dirname "${BASH_SOURCE[0]}")/tools.json")" 206 | 207 | curl_args=( 208 | "--fail" 209 | "--silent" 210 | "--location" 211 | "--output" "${dir}/yj" 212 | ) 213 | 214 | if [[ "${token}" != "" ]]; then 215 | curl_args+=("--header" "Authorization: Token ${token}") 216 | fi 217 | 218 | util::print::title "Installing yj ${version}" 219 | 220 | os=$(util::tools::os) 221 | arch=$(util::tools::arch) 222 | 223 | curl "https://github.com/sclevine/yj/releases/download/${version}/yj-${os}-${arch}" \ 224 | "${curl_args[@]}" 225 | 226 | chmod +x "${dir}/yj" 227 | else 228 | util::print::info "Using yj $("${dir}"/yj -v)" 229 | fi 230 | } 231 | 232 | function util::tools::packager::install () { 233 | local dir 234 | while [[ "${#}" != 0 ]]; do 235 | case "${1}" in 236 | --directory) 237 | dir="${2}" 238 | shift 2 239 | ;; 240 | 241 | *) 242 | util::print::error "unknown argument \"${1}\"" 243 | ;; 244 | 245 | esac 246 | done 247 | 248 | mkdir -p "${dir}" 249 | util::tools::path::export "${dir}" 250 | 251 | if [[ ! -f "${dir}/packager" ]]; then 252 | util::print::title "Installing packager" 253 | GOBIN="${dir}" go install github.com/cloudfoundry/libcfbuildpack/packager@latest 254 | fi 255 | } 256 | 257 | function util::tools::libpak-tools::install () { 258 | local dir token 259 | token="" 260 | 261 | while [[ "${#}" != 0 ]]; do 262 | case "${1}" in 263 | --directory) 264 | dir="${2}" 265 | shift 2 266 | ;; 267 | 268 | --token) 269 | token="${2}" 270 | shift 2 271 | ;; 272 | 273 | *) 274 | util::print::error "unknown argument \"${1}\"" 275 | esac 276 | done 277 | 278 | mkdir -p "${dir}" 279 | util::tools::path::export "${dir}" 280 | 281 | 282 | if [[ ! -f "${dir}/libpak-tools" ]]; then 283 | local version curl_args os arch 284 | 285 | version="$(jq -r .libpaktools "$(dirname "${BASH_SOURCE[0]}")/tools.json")" 286 | 287 | curl_args=( 288 | "--fail" 289 | "--silent" 290 | "--location" 291 | "--output" "${dir}/libpak-tools.tar.gz" 292 | ) 293 | 294 | if [[ "${token}" != "" ]]; then 295 | curl_args+=("--header" "Authorization: Token ${token}") 296 | fi 297 | 298 | util::print::title "Installing libpak-tools ${version}" 299 | 300 | os=$(util::tools::os) 301 | arch=$(util::tools::arch --format-amd64-x86_64) 302 | 303 | curl "https://github.com/paketo-buildpacks/libpak-tools/releases/download/${version}/libpak-tools_${os}_${arch}.tar.gz" \ 304 | "${curl_args[@]}" 305 | 306 | tar -xzf "${dir}/libpak-tools.tar.gz" -C $dir 307 | rm "${dir}/libpak-tools.tar.gz" 308 | 309 | chmod +x "${dir}/libpak-tools" 310 | else 311 | util::print::info "Using libpak-tools" 312 | fi 313 | } 314 | 315 | function util::tools::create-package::install () { 316 | local dir version 317 | while [[ "${#}" != 0 ]]; do 318 | case "${1}" in 319 | --directory) 320 | dir="${2}" 321 | shift 2 322 | ;; 323 | 324 | *) 325 | util::print::error "unknown argument \"${1}\"" 326 | ;; 327 | 328 | esac 329 | done 330 | 331 | version="$(jq -r .createpackage "$(dirname "${BASH_SOURCE[0]}")/tools.json")" 332 | 333 | mkdir -p "${dir}" 334 | util::tools::path::export "${dir}" 335 | 336 | if [[ ! -f "${dir}/create-package" ]]; then 337 | util::print::title "Installing create-package" 338 | GOBIN="${dir}" go install -ldflags="-s -w" "github.com/paketo-buildpacks/libpak/cmd/create-package@${version}" 339 | fi 340 | } 341 | 342 | function util::tools::tests::checkfocus() { 343 | testout="${1}" 344 | if grep -q 'Focused: [1-9]' "${testout}"; then 345 | echo "Detected Focused Test(s) - setting exit code to 197" 346 | rm "${testout}" 347 | util::print::success "** GO Test Succeeded **" 197 348 | fi 349 | rm "${testout}" 350 | } 351 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /integration/testdata/poetry-dep-only/poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "blinker" 5 | version = "1.7.0" 6 | description = "Fast, simple object-to-object and broadcast signaling" 7 | optional = false 8 | python-versions = ">=3.8" 9 | groups = ["main"] 10 | files = [ 11 | {file = "blinker-1.7.0-py3-none-any.whl", hash = "sha256:c3f865d4d54db7abc53758a01601cf343fe55b84c1de4e3fa910e420b438d5b9"}, 12 | {file = "blinker-1.7.0.tar.gz", hash = "sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182"}, 13 | ] 14 | 15 | [[package]] 16 | name = "click" 17 | version = "8.1.7" 18 | description = "Composable command line interface toolkit" 19 | optional = false 20 | python-versions = ">=3.7" 21 | groups = ["main"] 22 | files = [ 23 | {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, 24 | {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, 25 | ] 26 | 27 | [package.dependencies] 28 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 29 | 30 | [[package]] 31 | name = "colorama" 32 | version = "0.4.6" 33 | description = "Cross-platform colored terminal text." 34 | optional = false 35 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 36 | groups = ["main"] 37 | markers = "platform_system == \"Windows\"" 38 | files = [ 39 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 40 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 41 | ] 42 | 43 | [[package]] 44 | name = "flask" 45 | version = "2.3.3" 46 | description = "A simple framework for building complex web applications." 47 | optional = false 48 | python-versions = ">=3.8" 49 | groups = ["main"] 50 | files = [ 51 | {file = "flask-2.3.3-py3-none-any.whl", hash = "sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b"}, 52 | {file = "flask-2.3.3.tar.gz", hash = "sha256:09c347a92aa7ff4a8e7f3206795f30d826654baf38b873d0744cd571ca609efc"}, 53 | ] 54 | 55 | [package.dependencies] 56 | blinker = ">=1.6.2" 57 | click = ">=8.1.3" 58 | itsdangerous = ">=2.1.2" 59 | Jinja2 = ">=3.1.2" 60 | Werkzeug = ">=2.3.7" 61 | 62 | [package.extras] 63 | async = ["asgiref (>=3.2)"] 64 | dotenv = ["python-dotenv"] 65 | 66 | [[package]] 67 | name = "gunicorn" 68 | version = "20.1.0" 69 | description = "WSGI HTTP Server for UNIX" 70 | optional = false 71 | python-versions = ">=3.5" 72 | groups = ["main"] 73 | files = [ 74 | {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, 75 | {file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"}, 76 | ] 77 | 78 | [package.dependencies] 79 | setuptools = ">=3.0" 80 | 81 | [package.extras] 82 | eventlet = ["eventlet (>=0.24.1)"] 83 | gevent = ["gevent (>=1.4.0)"] 84 | setproctitle = ["setproctitle"] 85 | tornado = ["tornado (>=0.2)"] 86 | 87 | [[package]] 88 | name = "itsdangerous" 89 | version = "2.1.2" 90 | description = "Safely pass data to untrusted environments and back." 91 | optional = false 92 | python-versions = ">=3.7" 93 | groups = ["main"] 94 | files = [ 95 | {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, 96 | {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, 97 | ] 98 | 99 | [[package]] 100 | name = "jinja2" 101 | version = "3.1.3" 102 | description = "A very fast and expressive template engine." 103 | optional = false 104 | python-versions = ">=3.7" 105 | groups = ["main"] 106 | files = [ 107 | {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, 108 | {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, 109 | ] 110 | 111 | [package.dependencies] 112 | MarkupSafe = ">=2.0" 113 | 114 | [package.extras] 115 | i18n = ["Babel (>=2.7)"] 116 | 117 | [[package]] 118 | name = "markupsafe" 119 | version = "2.1.5" 120 | description = "Safely add untrusted strings to HTML/XML markup." 121 | optional = false 122 | python-versions = ">=3.7" 123 | groups = ["main"] 124 | files = [ 125 | {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, 126 | {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, 127 | {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, 128 | {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, 129 | {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, 130 | {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, 131 | {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, 132 | {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, 133 | {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, 134 | {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, 135 | {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, 136 | {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, 137 | {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, 138 | {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, 139 | {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, 140 | {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, 141 | {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, 142 | {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, 143 | {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, 144 | {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, 145 | {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, 146 | {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, 147 | {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, 148 | {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, 149 | {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, 150 | {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, 151 | {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, 152 | {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, 153 | {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, 154 | {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, 155 | {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, 156 | {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, 157 | {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, 158 | {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, 159 | {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, 160 | {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, 161 | {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, 162 | {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, 163 | {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, 164 | {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, 165 | {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, 166 | {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, 167 | {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, 168 | {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, 169 | {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, 170 | {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, 171 | {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, 172 | {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, 173 | {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, 174 | {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, 175 | {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, 176 | {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, 177 | {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, 178 | {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, 179 | {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, 180 | {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, 181 | {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, 182 | {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, 183 | {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, 184 | {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, 185 | ] 186 | 187 | [[package]] 188 | name = "setuptools" 189 | version = "69.1.0" 190 | description = "Easily download, build, install, upgrade, and uninstall Python packages" 191 | optional = false 192 | python-versions = ">=3.8" 193 | groups = ["main"] 194 | files = [ 195 | {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"}, 196 | {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"}, 197 | ] 198 | 199 | [package.extras] 200 | docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] 201 | testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov ; platform_python_implementation != \"PyPy\"", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1) ; platform_python_implementation != \"PyPy\"", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] 202 | testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] 203 | 204 | [[package]] 205 | name = "werkzeug" 206 | version = "3.0.1" 207 | description = "The comprehensive WSGI web application library." 208 | optional = false 209 | python-versions = ">=3.8" 210 | groups = ["main"] 211 | files = [ 212 | {file = "werkzeug-3.0.1-py3-none-any.whl", hash = "sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10"}, 213 | {file = "werkzeug-3.0.1.tar.gz", hash = "sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc"}, 214 | ] 215 | 216 | [package.dependencies] 217 | MarkupSafe = ">=2.1.1" 218 | 219 | [package.extras] 220 | watchdog = ["watchdog (>=2.3)"] 221 | 222 | [metadata] 223 | lock-version = "2.1" 224 | python-versions = "^3.12" 225 | content-hash = "99fb8cdd58f4517bbb6cb24379e15e53f9506a4d60979c15d68be34d1bb00d61" 226 | -------------------------------------------------------------------------------- /integration/testdata/poetry-run/poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "blinker" 5 | version = "1.9.0" 6 | description = "Fast, simple object-to-object and broadcast signaling" 7 | optional = false 8 | python-versions = ">=3.9" 9 | groups = ["main"] 10 | files = [ 11 | {file = "blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc"}, 12 | {file = "blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf"}, 13 | ] 14 | 15 | [[package]] 16 | name = "click" 17 | version = "8.3.0" 18 | description = "Composable command line interface toolkit" 19 | optional = false 20 | python-versions = ">=3.10" 21 | groups = ["main"] 22 | files = [ 23 | {file = "click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc"}, 24 | {file = "click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4"}, 25 | ] 26 | 27 | [package.dependencies] 28 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 29 | 30 | [[package]] 31 | name = "colorama" 32 | version = "0.4.6" 33 | description = "Cross-platform colored terminal text." 34 | optional = false 35 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 36 | groups = ["main"] 37 | markers = "platform_system == \"Windows\"" 38 | files = [ 39 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 40 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 41 | ] 42 | 43 | [[package]] 44 | name = "flask" 45 | version = "3.1.2" 46 | description = "A simple framework for building complex web applications." 47 | optional = false 48 | python-versions = ">=3.9" 49 | groups = ["main"] 50 | files = [ 51 | {file = "flask-3.1.2-py3-none-any.whl", hash = "sha256:ca1d8112ec8a6158cc29ea4858963350011b5c846a414cdb7a954aa9e967d03c"}, 52 | {file = "flask-3.1.2.tar.gz", hash = "sha256:bf656c15c80190ed628ad08cdfd3aaa35beb087855e2f494910aa3774cc4fd87"}, 53 | ] 54 | 55 | [package.dependencies] 56 | blinker = ">=1.9.0" 57 | click = ">=8.1.3" 58 | itsdangerous = ">=2.2.0" 59 | jinja2 = ">=3.1.2" 60 | markupsafe = ">=2.1.1" 61 | werkzeug = ">=3.1.0" 62 | 63 | [package.extras] 64 | async = ["asgiref (>=3.2)"] 65 | dotenv = ["python-dotenv"] 66 | 67 | [[package]] 68 | name = "itsdangerous" 69 | version = "2.2.0" 70 | description = "Safely pass data to untrusted environments and back." 71 | optional = false 72 | python-versions = ">=3.8" 73 | groups = ["main"] 74 | files = [ 75 | {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, 76 | {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, 77 | ] 78 | 79 | [[package]] 80 | name = "jinja2" 81 | version = "3.1.6" 82 | description = "A very fast and expressive template engine." 83 | optional = false 84 | python-versions = ">=3.7" 85 | groups = ["main"] 86 | files = [ 87 | {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, 88 | {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, 89 | ] 90 | 91 | [package.dependencies] 92 | MarkupSafe = ">=2.0" 93 | 94 | [package.extras] 95 | i18n = ["Babel (>=2.7)"] 96 | 97 | [[package]] 98 | name = "markupsafe" 99 | version = "3.0.3" 100 | description = "Safely add untrusted strings to HTML/XML markup." 101 | optional = false 102 | python-versions = ">=3.9" 103 | groups = ["main"] 104 | files = [ 105 | {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, 106 | {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, 107 | {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, 108 | {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, 109 | {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, 110 | {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, 111 | {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, 112 | {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, 113 | {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, 114 | {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, 115 | {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, 116 | {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, 117 | {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, 118 | {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, 119 | {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, 120 | {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, 121 | {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, 122 | {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, 123 | {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, 124 | {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, 125 | {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, 126 | {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, 127 | {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, 128 | {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, 129 | {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, 130 | {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, 131 | {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, 132 | {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, 133 | {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, 134 | {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, 135 | {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, 136 | {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, 137 | {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, 138 | {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, 139 | {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, 140 | {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, 141 | {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, 142 | {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, 143 | {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, 144 | {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, 145 | {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, 146 | {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, 147 | {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, 148 | {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, 149 | {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, 150 | {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, 151 | {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, 152 | {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, 153 | {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, 154 | {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, 155 | {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, 156 | {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, 157 | {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, 158 | {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, 159 | {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, 160 | {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, 161 | {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, 162 | {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, 163 | {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, 164 | {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, 165 | {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, 166 | {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, 167 | {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, 168 | {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, 169 | {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, 170 | {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, 171 | {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, 172 | {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, 173 | {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, 174 | {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, 175 | {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, 176 | {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, 177 | {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, 178 | {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, 179 | {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, 180 | {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, 181 | {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, 182 | {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, 183 | {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, 184 | {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, 185 | {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, 186 | {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, 187 | {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, 188 | {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, 189 | {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, 190 | {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, 191 | {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, 192 | {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, 193 | {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, 194 | ] 195 | 196 | [[package]] 197 | name = "werkzeug" 198 | version = "3.1.3" 199 | description = "The comprehensive WSGI web application library." 200 | optional = false 201 | python-versions = ">=3.9" 202 | groups = ["main"] 203 | files = [ 204 | {file = "werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e"}, 205 | {file = "werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746"}, 206 | ] 207 | 208 | [package.dependencies] 209 | MarkupSafe = ">=2.1.1" 210 | 211 | [package.extras] 212 | watchdog = ["watchdog (>=2.3)"] 213 | 214 | [metadata] 215 | lock-version = "2.1" 216 | python-versions = "3.14" 217 | content-hash = "96710f8bb9184fde30b7601336779a11eb4b0356c41063b5684000371b1133d2" 218 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= 2 | dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= 3 | github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= 4 | github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= 5 | github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= 6 | github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= 7 | github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= 8 | github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= 9 | github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= 10 | github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= 11 | github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= 12 | github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= 13 | github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= 14 | github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= 15 | github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= 16 | github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 17 | github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= 18 | github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= 19 | github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= 20 | github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= 21 | github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= 22 | github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= 23 | github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= 24 | github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= 25 | github.com/containerd/stargz-snapshotter/estargz v0.18.1 h1:cy2/lpgBXDA3cDKSyEfNOFMA/c10O1axL69EU7iirO8= 26 | github.com/containerd/stargz-snapshotter/estargz v0.18.1/go.mod h1:ALIEqa7B6oVDsrF37GkGN20SuvG/pIMm7FwP7ZmRb0Q= 27 | github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= 28 | github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= 29 | github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= 30 | github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= 31 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 32 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 33 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= 34 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 35 | github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= 36 | github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= 37 | github.com/docker/cli v29.0.3+incompatible h1:8J+PZIcF2xLd6h5sHPsp5pvvJA+Sr2wGQxHkRl53a1E= 38 | github.com/docker/cli v29.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= 39 | github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= 40 | github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= 41 | github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= 42 | github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 43 | github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8= 44 | github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo= 45 | github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= 46 | github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= 47 | github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= 48 | github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 49 | github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4= 50 | github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= 51 | github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A= 52 | github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= 53 | github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= 54 | github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= 55 | github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= 56 | github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= 57 | github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 58 | github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= 59 | github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 60 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 61 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 62 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 63 | github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= 64 | github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= 65 | github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= 66 | github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= 67 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 68 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 69 | github.com/google/go-containerregistry v0.20.7 h1:24VGNpS0IwrOZ2ms2P1QE3Xa5X9p4phx0aUgzYzHW6I= 70 | github.com/google/go-containerregistry v0.20.7/go.mod h1:Lx5LCZQjLH1QBaMPeGwsME9biPeo1lPx6lbGj/UmzgM= 71 | github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 h1:EEHtgt9IwisQ2AZ4pIsMjahcegHh6rmhqxzIRQIyepY= 72 | github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U= 73 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 74 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 75 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= 76 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= 77 | github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= 78 | github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= 79 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 80 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 81 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 82 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 83 | github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc= 84 | github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= 85 | github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= 86 | github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 87 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 88 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 89 | github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= 90 | github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= 91 | github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= 92 | github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= 93 | github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= 94 | github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= 95 | github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= 96 | github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= 97 | github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= 98 | github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= 99 | github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= 100 | github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= 101 | github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= 102 | github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= 103 | github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= 104 | github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= 105 | github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ= 106 | github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw= 107 | github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= 108 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= 109 | github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s= 110 | github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= 111 | github.com/onsi/ginkgo/v2 v2.25.3 h1:Ty8+Yi/ayDAGtk4XxmmfUy4GabvM+MegeB4cDLRi6nw= 112 | github.com/onsi/ginkgo/v2 v2.25.3/go.mod h1:43uiyQC4Ed2tkOzLsEYm7hnrb7UJTWHYNsuy3bG/snE= 113 | github.com/onsi/gomega v1.38.3 h1:eTX+W6dobAYfFeGC2PV6RwXRu/MyT+cQguijutvkpSM= 114 | github.com/onsi/gomega v1.38.3/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4= 115 | github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= 116 | github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= 117 | github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= 118 | github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= 119 | github.com/paketo-buildpacks/freezer v0.2.2 h1:p0qcGMQ54uGMzDFNkfpDpxddNl8+OTqt3teAWIkmCu4= 120 | github.com/paketo-buildpacks/freezer v0.2.2/go.mod h1:8dkcCqZKYFKxDV4MuooIR/Fr/LmpXqpr8R9mFvkGerE= 121 | github.com/paketo-buildpacks/occam v0.31.0 h1:OyKSqhFAT5gJB1wFENzl+LK0NSHG0/HBADIzP9lacvA= 122 | github.com/paketo-buildpacks/occam v0.31.0/go.mod h1:fbTuJwZDWW7mWmdyL7xpgOZMCyeHIQjpl5d0CMil2dM= 123 | github.com/paketo-buildpacks/packit/v2 v2.25.3 h1:oivXLVSEkp7bEbbQhWDbYF3y3lFItWtaCAkAu2MEdIQ= 124 | github.com/paketo-buildpacks/packit/v2 v2.25.3/go.mod h1:cNCDlkboN3ini3iTchIOiBcjt5cE7SModJQGja2XbGA= 125 | github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= 126 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 127 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 128 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 129 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 130 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 131 | github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= 132 | github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= 133 | github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= 134 | github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= 135 | github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8= 136 | github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM= 137 | github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAXZILTY= 138 | github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU= 139 | github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0= 140 | github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 141 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 142 | github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= 143 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 144 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 145 | github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= 146 | github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 147 | github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU= 148 | github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY= 149 | github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= 150 | github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= 151 | github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= 152 | github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= 153 | github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= 154 | github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 155 | github.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4= 156 | github.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA= 157 | github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= 158 | github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= 159 | go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= 160 | go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= 161 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= 162 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= 163 | go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= 164 | go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= 165 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= 166 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= 167 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 h1:wpMfgF8E1rkrT1Z6meFh1NDtownE9Ii3n3X2GJYjsaU= 168 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0/go.mod h1:wAy0T/dUbs468uOlkT31xjvqQgEVXv58BRFWEgn5v/0= 169 | go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= 170 | go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= 171 | go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= 172 | go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= 173 | go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= 174 | go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= 175 | go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= 176 | go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= 177 | go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= 178 | go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= 179 | go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= 180 | go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= 181 | go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= 182 | go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= 183 | golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= 184 | golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= 185 | golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= 186 | golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= 187 | golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= 188 | golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 189 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 190 | golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 191 | golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 192 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 193 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 194 | golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= 195 | golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 196 | golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= 197 | golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 198 | golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= 199 | golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 200 | golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= 201 | golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= 202 | golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= 203 | golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= 204 | google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk= 205 | google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4= 206 | google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= 207 | google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= 208 | google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= 209 | google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= 210 | google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= 211 | google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= 212 | google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= 213 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 214 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 215 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 216 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 217 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 218 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 219 | gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= 220 | gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= 221 | --------------------------------------------------------------------------------