├── .github ├── CODEOWNER ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── BUG-REPORT.yml │ ├── DESIGN-DOC.yml │ ├── FEATURE-REQUEST.yml │ └── config.yml ├── adopters │ ├── 3R-horiz.svg │ ├── allmyfunds.svg │ ├── arduino.svg │ ├── hootsuite.svg │ ├── kyma.svg │ ├── ordermygear.svg │ ├── raspi.svg │ ├── segment.svg │ ├── spiribo.svg │ ├── tulip.svg │ └── tw.svg ├── auto_assign.yml ├── config.yml ├── dependabot.yml ├── pull_request_template.md ├── stale.yml └── workflows │ ├── closed_references.yml │ ├── conventional_commits.yml │ ├── cve-scanner.yaml │ ├── format.yml │ ├── labels.yml │ ├── licenses.yml │ ├── stale.yml │ └── test.yml ├── .gitignore ├── .nancy-ignore ├── .prettierignore ├── .reference-ignore ├── .reports └── dep-licenses.csv ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── docker ├── AUTHORS ├── DOCKER-LICENSE ├── LICENSE ├── README.markdown ├── auth.go ├── change.go ├── client.go ├── client_unix.go ├── client_windows.go ├── container.go ├── distribution.go ├── env.go ├── event.go ├── exec.go ├── image.go ├── misc.go ├── network.go ├── opts │ ├── env.go │ ├── hosts.go │ ├── hosts_unix.go │ ├── hosts_windows.go │ ├── ip.go │ ├── opts.go │ ├── opts_unix.go │ ├── opts_windows.go │ ├── quotedstring.go │ ├── runtime.go │ └── ulimit.go ├── pkg │ ├── README.md │ ├── archive │ │ ├── README.md │ │ ├── archive.go │ │ ├── archive_linux.go │ │ ├── archive_other.go │ │ ├── archive_unix.go │ │ ├── archive_windows.go │ │ ├── changes.go │ │ ├── changes_linux.go │ │ ├── changes_other.go │ │ ├── changes_unix.go │ │ ├── changes_windows.go │ │ ├── copy.go │ │ ├── copy_unix.go │ │ ├── copy_windows.go │ │ ├── diff.go │ │ ├── example_changes.go │ │ ├── testdata │ │ │ └── broken.tar │ │ ├── time_linux.go │ │ ├── time_unsupported.go │ │ ├── whiteouts.go │ │ └── wrap.go │ ├── fileutils │ │ ├── fileutils.go │ │ ├── fileutils_darwin.go │ │ ├── fileutils_unix.go │ │ └── fileutils_windows.go │ ├── homedir │ │ ├── homedir_linux.go │ │ ├── homedir_others.go │ │ ├── homedir_unix.go │ │ └── homedir_windows.go │ ├── idtools │ │ ├── idtools.go │ │ ├── idtools_unix.go │ │ ├── idtools_windows.go │ │ ├── usergroupadd_linux.go │ │ ├── usergroupadd_unsupported.go │ │ └── utils_unix.go │ ├── ioutils │ │ ├── buffer.go │ │ ├── bytespipe.go │ │ ├── fswriters.go │ │ ├── readers.go │ │ ├── temp_unix.go │ │ ├── temp_windows.go │ │ ├── writeflusher.go │ │ └── writers.go │ ├── jsonmessage │ │ └── jsonmessage.go │ ├── longpath │ │ └── longpath.go │ ├── mount │ │ ├── flags.go │ │ ├── flags_freebsd.go │ │ ├── flags_linux.go │ │ ├── flags_unsupported.go │ │ ├── mount.go │ │ ├── mounter_freebsd.go │ │ ├── mounter_linux.go │ │ ├── mounter_unsupported.go │ │ ├── mountinfo.go │ │ ├── mountinfo_freebsd.go │ │ ├── mountinfo_linux.go │ │ ├── mountinfo_unsupported.go │ │ ├── mountinfo_windows.go │ │ └── sharedsubtree_linux.go │ ├── pools │ │ └── pools.go │ ├── stdcopy │ │ └── stdcopy.go │ └── system │ │ ├── chtimes.go │ │ ├── chtimes_unix.go │ │ ├── chtimes_windows.go │ │ ├── errors.go │ │ ├── exitcode.go │ │ ├── filesys.go │ │ ├── filesys_windows.go │ │ ├── init.go │ │ ├── init_unix.go │ │ ├── init_windows.go │ │ ├── lcow.go │ │ ├── lcow_unix.go │ │ ├── lcow_windows.go │ │ ├── lstat_unix.go │ │ ├── lstat_windows.go │ │ ├── meminfo.go │ │ ├── meminfo_linux.go │ │ ├── meminfo_unsupported.go │ │ ├── meminfo_windows.go │ │ ├── mknod.go │ │ ├── mknod_freebsd.go │ │ ├── mknod_windows.go │ │ ├── path.go │ │ ├── process_unix.go │ │ ├── process_windows.go │ │ ├── rm.go │ │ ├── stat_darwin.go │ │ ├── stat_freebsd.go │ │ ├── stat_linux.go │ │ ├── stat_openbsd.go │ │ ├── stat_solaris.go │ │ ├── stat_unix.go │ │ ├── stat_windows.go │ │ ├── syscall_unix.go │ │ ├── syscall_windows.go │ │ ├── umask.go │ │ ├── umask_windows.go │ │ ├── utimes_freebsd.go │ │ ├── utimes_linux.go │ │ ├── utimes_unsupported.go │ │ ├── xattrs_linux.go │ │ └── xattrs_unsupported.go ├── plugin.go ├── registry_auth.go ├── signal.go ├── tar.go ├── tls.go ├── types │ ├── auth.go │ ├── blkiodev │ │ └── blkio.go │ ├── client.go │ ├── configs.go │ ├── container │ │ ├── config.go │ │ ├── container_changes.go │ │ ├── container_create.go │ │ ├── container_top.go │ │ ├── container_update.go │ │ ├── container_wait.go │ │ ├── host_config.go │ │ ├── hostconfig_unix.go │ │ ├── hostconfig_windows.go │ │ └── waitcondition.go │ ├── error_response.go │ ├── filters │ │ ├── example_test.go │ │ ├── parse.go │ │ └── parse_test.go │ ├── graph_driver_data.go │ ├── id_response.go │ ├── image_delete_response_item.go │ ├── image_summary.go │ ├── mount │ │ └── mount.go │ ├── network │ │ └── network.go │ ├── plugin.go │ ├── plugin_device.go │ ├── plugin_env.go │ ├── plugin_interface_type.go │ ├── plugin_mount.go │ ├── plugin_responses.go │ ├── port.go │ ├── registry │ │ ├── authenticate.go │ │ └── registry.go │ ├── seccomp.go │ ├── service_update_response.go │ ├── stats.go │ ├── strslice │ │ ├── strslice.go │ │ └── strslice_test.go │ ├── types.go │ ├── versions │ │ ├── README.md │ │ ├── compare.go │ │ ├── compare_test.go │ │ ├── v1p19 │ │ │ └── types.go │ │ └── v1p20 │ │ │ └── types.go │ └── volume.go └── volume.go ├── dockertest.go ├── dockertest_test.go ├── docs └── images │ └── banner_dockertest.png ├── examples ├── BuildDockerfile.md ├── Cassandra.md ├── CockroachDB.md ├── FakeGoogleCloudStorage.md ├── Kafka.md ├── Minio.md ├── MongoDB.md ├── Mountebank.md ├── MultipleTestContainers.md ├── MySQL.md ├── PostgreSQL.md ├── Redis.md └── RethinkDB.md ├── go.mod ├── go.sum ├── package-lock.json └── package.json /.github/CODEOWNER: -------------------------------------------------------------------------------- 1 | * @ory/maintainers 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # AUTO-GENERATED, DO NOT EDIT! 2 | # Please edit the original at https://github.com/ory/meta/blob/master/templates/repository/common/.github/FUNDING.yml 3 | 4 | # These are supported funding model platforms 5 | 6 | # github: 7 | patreon: _ory 8 | open_collective: ory 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml: -------------------------------------------------------------------------------- 1 | # AUTO-GENERATED, DO NOT EDIT! 2 | # Please edit the original at https://github.com/ory/meta/blob/master/templates/repository/common/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml 3 | 4 | description: 5 | "Suggest an idea for this project without a plan for implementation" 6 | labels: 7 | - feat 8 | name: "Feature Request" 9 | body: 10 | - attributes: 11 | value: | 12 | Thank you for suggesting an idea for this project! 13 | 14 | If you already have a plan to implement a feature or a change, please create a [design document](https://github.com/aeneasr/gh-template-test/issues/new?assignees=&labels=rfc&template=DESIGN-DOC.yml) instead if the change is non-trivial! 15 | type: markdown 16 | - attributes: 17 | label: "Preflight checklist" 18 | options: 19 | - label: 20 | "I could not find a solution in the existing issues, docs, nor 21 | discussions." 22 | required: true 23 | - label: 24 | "I agree to follow this project's [Code of 25 | Conduct](https://github.com/ory/dockertest/blob/master/CODE_OF_CONDUCT.md)." 26 | required: true 27 | - label: 28 | "I have read and am following this repository's [Contribution 29 | Guidelines](https://github.com/ory/dockertest/blob/master/CONTRIBUTING.md)." 30 | required: true 31 | - label: 32 | "I have joined the [Ory Community Slack](https://slack.ory.sh)." 33 | - label: 34 | "I am signed up to the [Ory Security Patch 35 | Newsletter](https://www.ory.sh/l/sign-up-newsletter)." 36 | id: checklist 37 | type: checkboxes 38 | - attributes: 39 | description: 40 | "Enter the slug or API URL of the affected Ory Network project. Leave 41 | empty when you are self-hosting." 42 | label: "Ory Network Project" 43 | placeholder: "https://.projects.oryapis.com" 44 | id: ory-network-project 45 | type: input 46 | - attributes: 47 | description: 48 | "Is your feature request related to a problem? Please describe." 49 | label: "Describe your problem" 50 | placeholder: 51 | "A clear and concise description of what the problem is. Ex. I'm always 52 | frustrated when [...]" 53 | id: problem 54 | type: textarea 55 | validations: 56 | required: true 57 | - attributes: 58 | description: | 59 | Describe the solution you'd like 60 | placeholder: | 61 | A clear and concise description of what you want to happen. 62 | label: "Describe your ideal solution" 63 | id: solution 64 | type: textarea 65 | validations: 66 | required: true 67 | - attributes: 68 | description: "Describe alternatives you've considered" 69 | label: "Workarounds or alternatives" 70 | id: alternatives 71 | type: textarea 72 | validations: 73 | required: true 74 | - attributes: 75 | description: "What version of our software are you running?" 76 | label: Version 77 | id: version 78 | type: input 79 | validations: 80 | required: true 81 | - attributes: 82 | description: 83 | "Add any other context or screenshots about the feature request here." 84 | label: Additional Context 85 | id: additional 86 | type: textarea 87 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | # AUTO-GENERATED, DO NOT EDIT! 2 | # Please edit the original at https://github.com/ory/meta/blob/master/templates/repository/common/.github/ISSUE_TEMPLATE/config.yml 3 | 4 | blank_issues_enabled: false 5 | contact_links: 6 | - name: Ory Dockertest Forum 7 | url: https://github.com/orgs/ory/discussions 8 | about: 9 | Please ask and answer questions here, show your implementations and 10 | discuss ideas. 11 | - name: Ory Chat 12 | url: https://www.ory.sh/chat 13 | about: 14 | Hang out with other Ory community members to ask and answer questions. 15 | -------------------------------------------------------------------------------- /.github/adopters/3R-horiz.svg: -------------------------------------------------------------------------------- 1 | 4 | 6 | 14 | 21 | 29 | 36 | 39 | 41 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /.github/adopters/ordermygear.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ORDER 22 | MY 23 | GEAR 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /.github/adopters/tw.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.github/auto_assign.yml: -------------------------------------------------------------------------------- 1 | # AUTO-GENERATED, DO NOT EDIT! 2 | # Please edit the original at https://github.com/ory/meta/blob/master/templates/repository/common/.github/auto_assign.yml 3 | 4 | # Set to true to add reviewers to pull requests 5 | addReviewers: true 6 | 7 | # Set to true to add assignees to pull requests 8 | addAssignees: true 9 | 10 | # A list of reviewers to be added to pull requests (GitHub user name) 11 | assignees: 12 | - ory/maintainers 13 | 14 | # A number of reviewers added to the pull request 15 | # Set 0 to add all the reviewers (default: 0) 16 | numberOfReviewers: 0 17 | -------------------------------------------------------------------------------- /.github/config.yml: -------------------------------------------------------------------------------- 1 | # AUTO-GENERATED, DO NOT EDIT! 2 | # Please edit the original at https://github.com/ory/meta/blob/master/templates/repository/common/.github/config.yml 3 | 4 | todo: 5 | keyword: "@todo" 6 | label: todo 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | open-pull-requests-limit: 10 8 | - package-ecosystem: github-actions 9 | directory: "/" 10 | schedule: 11 | interval: weekly 12 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 12 | 13 | ## Related Issue or Design Document 14 | 15 | 29 | 30 | ## Checklist 31 | 32 | 36 | 37 | - [ ] I have read the [contributing guidelines](../blob/master/CONTRIBUTING.md) and signed the CLA. 38 | - [ ] I have referenced an issue containing the design document if my change introduces a new feature. 39 | - [ ] I have read the [security policy](../security/policy). 40 | - [ ] I confirm that this pull request does not address a security vulnerability. 41 | If this pull request addresses a security vulnerability, 42 | I confirm that I got approval (please contact [security@ory.sh](mailto:security@ory.sh)) from the maintainers to push the changes. 43 | - [ ] I have added tests that prove my fix is effective or that my feature works. 44 | - [ ] I have added the necessary documentation within the code base (if appropriate). 45 | 46 | ## Further comments 47 | 48 | 52 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 1 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 2 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: stale 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | Thank you for your contribution, we value it! However, this issue has been 14 | marked as stale because it has not had recent activity, or because it does not 15 | comply with our contribution guidelines. If it is the latter, please follow 16 | the instructions from the comment above to comply with our guidelines. It will 17 | be closed if no further activity occurs. Thank you for your contributions. 18 | # Comment to post when closing a stale issue. Set to `false` to disable 19 | closeComment: false 20 | 21 | # Set to true to ignore issues in a project (defaults to false) 22 | exemptProjects: false 23 | 24 | # Set to true to ignore issues in a milestone (defaults to false) 25 | exemptMilestones: false 26 | 27 | # Set to true to ignore issues with an assignee (defaults to false) 28 | exemptAssignees: false 29 | 30 | onlyLabels: 31 | - needs-context 32 | -------------------------------------------------------------------------------- /.github/workflows/closed_references.yml: -------------------------------------------------------------------------------- 1 | # AUTO-GENERATED, DO NOT EDIT! 2 | # Please edit the original at https://github.com/ory/meta/blob/master/templates/repository/common/.github/workflows/closed_references.yml 3 | 4 | name: Closed Reference Notifier 5 | 6 | on: 7 | schedule: 8 | - cron: "0 0 * * *" 9 | workflow_dispatch: 10 | inputs: 11 | issueLimit: 12 | description: Max. number of issues to create 13 | required: true 14 | default: "5" 15 | 16 | jobs: 17 | find_closed_references: 18 | if: github.repository_owner == 'ory' 19 | runs-on: ubuntu-latest 20 | name: Find closed references 21 | steps: 22 | - uses: actions/checkout@v2 23 | - uses: actions/setup-node@v4.3.0 24 | with: 25 | node-version: "14" 26 | - uses: ory/closed-reference-notifier@v1 27 | with: 28 | token: ${{ secrets.GITHUB_TOKEN }} 29 | issueLabels: upstream,good first issue,help wanted 30 | issueLimit: ${{ github.event.inputs.issueLimit || '5' }} 31 | -------------------------------------------------------------------------------- /.github/workflows/conventional_commits.yml: -------------------------------------------------------------------------------- 1 | # AUTO-GENERATED, DO NOT EDIT! 2 | # Please edit the original at https://github.com/ory/meta/blob/master/templates/repository/common/.github/workflows/conventional_commits.yml 3 | 4 | name: Conventional commits 5 | 6 | # This GitHub CI Action enforces that pull request titles follow conventional commits. 7 | # More info at https://www.conventionalcommits.org. 8 | # 9 | # The Ory-wide defaults for commit titles and scopes are below. 10 | # Your repository can add/replace elements via a configuration file at the path below. 11 | # More info at https://github.com/ory/ci/blob/master/conventional_commit_config/README.md 12 | 13 | on: 14 | pull_request_target: 15 | types: 16 | - edited 17 | - opened 18 | - ready_for_review 19 | - reopened 20 | # pull_request: # for debugging, uses config in local branch but supports only Pull Requests from this repo 21 | 22 | jobs: 23 | main: 24 | name: Validate PR title 25 | runs-on: ubuntu-latest 26 | steps: 27 | - uses: actions/checkout@v3 28 | - id: config 29 | uses: ory/ci/conventional_commit_config@master 30 | with: 31 | config_path: .github/conventional_commits.json 32 | default_types: | 33 | feat 34 | fix 35 | revert 36 | docs 37 | style 38 | refactor 39 | test 40 | build 41 | autogen 42 | security 43 | ci 44 | chore 45 | default_scopes: | 46 | deps 47 | docs 48 | default_require_scope: false 49 | - uses: amannn/action-semantic-pull-request@v4 50 | env: 51 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 52 | with: 53 | types: ${{ steps.config.outputs.types }} 54 | scopes: ${{ steps.config.outputs.scopes }} 55 | requireScope: ${{ steps.config.outputs.requireScope }} 56 | subjectPattern: ^(?![A-Z]).+$ 57 | subjectPatternError: | 58 | The subject should start with a lowercase letter, yours is uppercase: 59 | "{subject}" 60 | -------------------------------------------------------------------------------- /.github/workflows/cve-scanner.yaml: -------------------------------------------------------------------------------- 1 | name: Go Source Scanners 2 | on: 3 | push: 4 | branches: 5 | - "master" 6 | - "v*.*.*" 7 | - "v*" 8 | tags: 9 | - "v*.*.*" 10 | pull_request: 11 | branches: 12 | - "master" 13 | - "v*.*.*" 14 | - "v*" 15 | 16 | jobs: 17 | scanners: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v4 22 | - name: Setup Env 23 | id: vars 24 | shell: bash 25 | run: | 26 | echo "SHA_SHORT=$(git rev-parse --short HEAD)" >> "${GITHUB_ENV}" 27 | - name: Run Gosec Security Scanner 28 | continue-on-error: true 29 | uses: securego/gosec@master 30 | with: 31 | args: ./... 32 | - name: Run Govulncheck Scanner 33 | continue-on-error: true 34 | uses: golang/govulncheck-action@v1 35 | with: 36 | go-package: ./... 37 | go-version-input: "1.22" 38 | - name: Run Trivy vulnerability scanner in repo mode 39 | continue-on-error: true 40 | uses: aquasecurity/trivy-action@master 41 | with: 42 | scan-type: "fs" 43 | ignore-unfixed: true 44 | format: "json" 45 | -------------------------------------------------------------------------------- /.github/workflows/format.yml: -------------------------------------------------------------------------------- 1 | name: Format 2 | 3 | on: 4 | pull_request: 5 | push: 6 | 7 | jobs: 8 | format: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-go@v5 13 | with: 14 | go-version: 1.22 15 | - run: make format 16 | - name: Indicate formatting issues 17 | run: git diff HEAD --exit-code --color 18 | -------------------------------------------------------------------------------- /.github/workflows/labels.yml: -------------------------------------------------------------------------------- 1 | # AUTO-GENERATED, DO NOT EDIT! 2 | # Please edit the original at https://github.com/ory/meta/blob/master/templates/repository/common/.github/workflows/labels.yml 3 | 4 | name: Synchronize Issue Labels 5 | 6 | on: 7 | workflow_dispatch: 8 | push: 9 | branches: 10 | - master 11 | 12 | jobs: 13 | milestone: 14 | if: github.repository_owner == 'ory' 15 | name: Synchronize Issue Labels 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v2 20 | - name: Synchronize Issue Labels 21 | uses: ory/label-sync-action@v0 22 | with: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | dry: false 25 | forced: true 26 | -------------------------------------------------------------------------------- /.github/workflows/licenses.yml: -------------------------------------------------------------------------------- 1 | # AUTO-GENERATED, DO NOT EDIT! 2 | # Please edit the original at https://github.com/ory/meta/blob/master/templates/repository/common/.github/workflows/licenses.yml 3 | 4 | name: Licenses 5 | 6 | on: 7 | pull_request: 8 | push: 9 | branches: 10 | - main 11 | - v3 12 | - master 13 | 14 | jobs: 15 | licenses: 16 | name: License compliance 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Install script 20 | uses: ory/ci/licenses/setup@master 21 | with: 22 | token: ${{ secrets.ORY_BOT_PAT || secrets.GITHUB_TOKEN }} 23 | - name: Check licenses 24 | uses: ory/ci/licenses/check@master 25 | - name: Write, commit, push licenses 26 | uses: ory/ci/licenses/write@master 27 | if: 28 | ${{ github.ref == 'refs/heads/main' || github.ref == 29 | 'refs/heads/master' || github.ref == 'refs/heads/v3' }} 30 | with: 31 | author-email: 32 | ${{ secrets.ORY_BOT_PAT && 33 | '60093411+ory-bot@users.noreply.github.com' || 34 | format('{0}@users.noreply.github.com', github.actor) }} 35 | author-name: ${{ secrets.ORY_BOT_PAT && 'ory-bot' || github.actor }} 36 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | # AUTO-GENERATED, DO NOT EDIT! 2 | # Please edit the original at https://github.com/ory/meta/blob/master/templates/repository/common/.github/workflows/stale.yml 3 | 4 | name: "Close Stale Issues" 5 | on: 6 | workflow_dispatch: 7 | schedule: 8 | - cron: "0 0 * * *" 9 | 10 | jobs: 11 | stale: 12 | if: github.repository_owner == 'ory' 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/stale@v4 16 | with: 17 | repo-token: ${{ secrets.GITHUB_TOKEN }} 18 | stale-issue-message: | 19 | Hello contributors! 20 | 21 | I am marking this issue as stale as it has not received any engagement from the community or maintainers for a year. That does not imply that the issue has no merit! If you feel strongly about this issue 22 | 23 | - open a PR referencing and resolving the issue; 24 | - leave a comment on it and discuss ideas on how you could contribute towards resolving it; 25 | - leave a comment and describe in detail why this issue is critical for your use case; 26 | - open a new issue with updated details and a plan for resolving the issue. 27 | 28 | Throughout its lifetime, Ory has received over 10.000 issues and PRs. To sustain that growth, we need to prioritize and focus on issues that are important to the community. A good indication of importance, and thus priority, is activity on a topic. 29 | 30 | Unfortunately, [burnout](https://www.jeffgeerling.com/blog/2016/why-i-close-prs-oss-project-maintainer-notes) has become a [topic](https://opensource.guide/best-practices/#its-okay-to-hit-pause) of [concern](https://docs.brew.sh/Maintainers-Avoiding-Burnout) amongst open-source projects. 31 | 32 | It can lead to severe personal and health issues as well as [opening](https://haacked.com/archive/2019/05/28/maintainer-burnout/) catastrophic [attack vectors](https://www.gradiant.org/en/blog/open-source-maintainer-burnout-as-an-attack-surface/). 33 | 34 | The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone. 35 | 36 | If this issue was marked as stale erroneously you can exempt it by adding the `backlog` label, assigning someone, or setting a milestone for it. 37 | 38 | Thank you for your understanding and to anyone who participated in the conversation! And as written above, please do participate in the conversation if this topic is important to you! 39 | 40 | Thank you 🙏✌️ 41 | stale-issue-label: "stale" 42 | exempt-issue-labels: "bug,blocking,docs,backlog" 43 | days-before-stale: 365 44 | days-before-close: 30 45 | exempt-milestones: true 46 | exempt-assignees: true 47 | only-pr-labels: "stale" 48 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test CI 2 | on: 3 | push: 4 | branches: 5 | - master 6 | - v3 7 | pull_request: 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - uses: actions/setup-go@v5 14 | with: 15 | go-version: "1.22" 16 | - run: make test 17 | - name: WriteGoList 18 | run: go list -json -deps ./... > go.list 19 | - name: Nancy 20 | uses: sonatype-nexus-community/nancy-github-action@main 21 | - name: Coveralls 22 | run: bash <(curl -s https://codecov.io/bash) 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bin/ 2 | .idea/ 3 | node_modules/ 4 | *.iml 5 | *.exe 6 | .cover/ 7 | vendor/ 8 | go.list 9 | cover.out 10 | coverage.out 11 | .vscode 12 | .bin/ 13 | -------------------------------------------------------------------------------- /.nancy-ignore: -------------------------------------------------------------------------------- 1 | CVE-2023-27561 # see https://github.com/sonatype-nexus-community/nancy/issues/273 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .github/pull_request_template.md 2 | CONTRIBUTING.md 3 | -------------------------------------------------------------------------------- /.reference-ignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | docs 3 | CHANGELOG.md 4 | -------------------------------------------------------------------------------- /.reports/dep-licenses.csv: -------------------------------------------------------------------------------- 1 | 2 | "github.com/Microsoft/go-winio","MIT" 3 | "github.com/Nvveen/Gotty","BSD-2-Clause" 4 | "github.com/docker/go-connections","Apache-2.0" 5 | "github.com/docker/go-units","Apache-2.0" 6 | "filippo.io/edwards25519","BSD-3-Clause" 7 | "github.com/go-sql-driver/mysql","MPL-2.0" 8 | "github.com/lib/pq","MIT" 9 | "github.com/moby/term","Apache-2.0" 10 | "golang.org/x/sys/unix","BSD-3-Clause" 11 | "github.com/sirupsen/logrus","MIT" 12 | "golang.org/x/sys/unix","BSD-3-Clause" 13 | "github.com/stretchr/testify","MIT" 14 | 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | format: .bin/ory node_modules # formats the source code 2 | .bin/ory dev headers copyright --type=open-source 3 | gofmt -l -s -w . 4 | npm exec -- prettier --write . 5 | 6 | help: 7 | cat Makefile | grep '^[^ ]*:' | grep -v '^\.bin/' | grep -v '.SILENT:' | grep -v '^node_modules:' | grep -v help | sed 's/:.*#/#/' | column -s "#" -t 8 | 9 | licenses: .bin/licenses node_modules # checks open-source licenses 10 | .bin/licenses 11 | 12 | .bin/licenses: Makefile 13 | curl https://raw.githubusercontent.com/ory/ci/master/licenses/install | sh 14 | 15 | .bin/ory: Makefile 16 | curl https://raw.githubusercontent.com/ory/meta/master/install.sh | bash -s -- -b .bin ory v0.3.2 17 | touch .bin/ory 18 | 19 | node_modules: package-lock.json 20 | npm install 21 | touch node_modules 22 | 23 | test: 24 | go mod tidy 25 | go vet -x . 26 | go test -covermode=atomic -coverprofile="coverage.out" . 27 | 28 | 29 | .DEFAULT_GOAL := help 30 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Ory Security Policy 5 | 6 | This policy outlines Ory's security commitments and practices for users across 7 | different licensing and deployment models. 8 | 9 | To learn more about Ory's security service level agreements (SLAs) and 10 | processes, please [contact us](https://www.ory.sh/contact/). 11 | 12 | ## Ory Network Users 13 | 14 | - **Security SLA:** Ory addresses vulnerabilities in the Ory Network according 15 | to the following guidelines: 16 | - Critical: Typically addressed within 14 days. 17 | - High: Typically addressed within 30 days. 18 | - Medium: Typically addressed within 90 days. 19 | - Low: Typically addressed within 180 days. 20 | - Informational: Addressed as necessary. 21 | These timelines are targets and may vary based on specific circumstances. 22 | - **Release Schedule:** Updates are deployed to the Ory Network as 23 | vulnerabilities are resolved. 24 | - **Version Support:** The Ory Network always runs the latest version, ensuring 25 | up-to-date security fixes. 26 | 27 | ## Ory Enterprise License Customers 28 | 29 | - **Security SLA:** Ory addresses vulnerabilities based on their severity: 30 | - Critical: Typically addressed within 14 days. 31 | - High: Typically addressed within 30 days. 32 | - Medium: Typically addressed within 90 days. 33 | - Low: Typically addressed within 180 days. 34 | - Informational: Addressed as necessary. 35 | These timelines are targets and may vary based on specific circumstances. 36 | - **Release Schedule:** Updates are made available as vulnerabilities are 37 | resolved. Ory works closely with enterprise customers to ensure timely updates 38 | that align with their operational needs. 39 | - **Version Support:** Ory may provide security support for multiple versions, 40 | depending on the terms of the enterprise agreement. 41 | 42 | ## Apache 2.0 License Users 43 | 44 | - **Security SLA:** Ory does not provide a formal SLA for security issues under 45 | the Apache 2.0 License. 46 | - **Release Schedule:** Releases prioritize new functionality and include fixes 47 | for known security vulnerabilities at the time of release. While major 48 | releases typically occur one to two times per year, Ory does not guarantee a 49 | fixed release schedule. 50 | - **Version Support:** Security patches are only provided for the latest release 51 | version. 52 | 53 | ## Reporting a Vulnerability 54 | 55 | For details on how to report security vulnerabilities, visit our 56 | [security policy documentation](https://www.ory.sh/docs/ecosystem/security). 57 | -------------------------------------------------------------------------------- /docker/AUTHORS: -------------------------------------------------------------------------------- 1 | # This is the official list of go-dockerclient authors for copyright purposes. 2 | 3 | Abhishek Chanda 4 | Adam Bell-Hanssen 5 | Adnan Khan 6 | Adrien Kohlbecker 7 | Aldrin Leal 8 | Alex Dadgar 9 | Alfonso Acosta 10 | André Carvalho 11 | Andreas Jaekle 12 | Andrew Snodgrass 13 | Andrews Medina 14 | Andrey Sibiryov 15 | Andy Goldstein 16 | Anirudh Aithal 17 | Antonio Murdaca 18 | Artem Sidorenko 19 | Arthur Rodrigues 20 | Ben Marini 21 | Ben McCann 22 | Ben Parees 23 | Benno van den Berg 24 | Bradley Cicenas 25 | Brendan Fosberry 26 | Brian Lalor 27 | Brian P. Hamachek 28 | Brian Palmer 29 | Bryan Boreham 30 | Burke Libbey 31 | Carlos Diaz-Padron 32 | Carson A 33 | Cássio Botaro 34 | Cesar Wong 35 | Cezar Sa Espinola 36 | Changping Chen 37 | Cheah Chu Yeow 38 | cheneydeng 39 | Chris Bednarski 40 | Chris Stavropoulos 41 | Christian Stewart 42 | Christophe Mourette 43 | Clayton Coleman 44 | Clint Armstrong 45 | CMGS 46 | Colin Hebert 47 | Craig Jellick 48 | Damien Lespiau 49 | Damon Wang 50 | Dan Williams 51 | Daniel, Dao Quang Minh 52 | Daniel Garcia 53 | Daniel Hiltgen 54 | Daniel Nephin 55 | Daniel Tsui 56 | Darren Shepherd 57 | Dave Choi 58 | David Huie 59 | Dawn Chen 60 | Denis Makogon 61 | Derek Petersen 62 | Dinesh Subhraveti 63 | Drew Wells 64 | Ed 65 | Elias G. Schneevoigt 66 | Erez Horev 67 | Eric Anderson 68 | Eric J. Holmes 69 | Eric Mountain 70 | Erwin van Eyk 71 | Ethan Mosbaugh 72 | Ewout Prangsma 73 | Fabio Rehm 74 | Fatih Arslan 75 | Felipe Oliveira 76 | Flavia Missi 77 | Florent Aide 78 | Francisco Souza 79 | Frank Groeneveld 80 | George Moura 81 | Grégoire Delattre 82 | Guilherme Rezende 83 | Guillermo Álvarez Fernández 84 | Harry Zhang 85 | He Simei 86 | Isaac Schnitzer 87 | Ivan Mikushin 88 | James Bardin 89 | James Nugent 90 | Jamie Snell 91 | Januar Wayong 92 | Jari Kolehmainen 93 | Jason Wilder 94 | Jawher Moussa 95 | Jean-Baptiste Dalido 96 | Jeff Mitchell 97 | Jeffrey Hulten 98 | Jen Andre 99 | Jérôme Laurens 100 | Jim Minter 101 | Johan Euphrosine 102 | Johannes Scheuermann 103 | John Hughes 104 | Jorge Marey 105 | Julian Einwag 106 | Kamil Domanski 107 | Karan Misra 108 | Ken Herner 109 | Kevin Lin 110 | Kevin Xu 111 | Kim, Hirokuni 112 | Kostas Lekkas 113 | Kyle Allan 114 | Yunhee Lee 115 | Liron Levin 116 | Lior Yankovich 117 | Liu Peng 118 | Lorenz Leutgeb 119 | Lucas Clemente 120 | Lucas Weiblen 121 | Lyon Hill 122 | Mantas Matelis 123 | Manuel Vogel 124 | Marguerite des Trois Maisons 125 | Mariusz Borsa 126 | Martin Sweeney 127 | Máximo Cuadros Ortiz 128 | Michael Schmatz 129 | Michal Fojtik 130 | Mike Dillon 131 | Mrunal Patel 132 | Nate Jones 133 | Nguyen Sy Thanh Son 134 | Nicholas Van Wiggeren 135 | Nick Ethier 136 | niko83 137 | Omeid Matten 138 | Orivej Desh 139 | Paul Bellamy 140 | Paul Morie 141 | Paul Weil 142 | Peter Edge 143 | Peter Jihoon Kim 144 | Peter Teich 145 | Phil Lu 146 | Philippe Lafoucrière 147 | Radek Simko 148 | Rafe Colton 149 | Raphaël Pinson 150 | Reed Allman 151 | RJ Catalano 152 | Rob Miller 153 | Robbert Klarenbeek 154 | Robert Williamson 155 | Roman Khlystik 156 | Russell Haering 157 | Salvador Gironès 158 | Sam Rijs 159 | Sami Wagiaalla 160 | Samuel Archambault 161 | Samuel Karp 162 | Sebastian Borza 163 | Seth Jennings 164 | Shane Xie 165 | Silas Sewell 166 | Simon Eskildsen 167 | Simon Menke 168 | Skolos 169 | Soulou 170 | Sridhar Ratnakumar 171 | Steven Jack 172 | Summer Mousa 173 | Sunjin Lee 174 | Sunny 175 | Swaroop Ramachandra 176 | Tarsis Azevedo 177 | Tim Schindler 178 | Timothy St. Clair 179 | Tobi Knaup 180 | Tom Wilkie 181 | Tonic 182 | ttyh061 183 | upccup 184 | Victor Marmol 185 | Vincenzo Prignano 186 | Vlad Alexandru Ionescu 187 | Weitao Zhou 188 | Wiliam Souza 189 | Ye Yin 190 | Yosuke Otosu 191 | Yu, Zou 192 | Yuriy Bogdanov 193 | -------------------------------------------------------------------------------- /docker/DOCKER-LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | You can find the Docker license at the following link: 6 | https://raw.githubusercontent.com/docker/docker/master/LICENSE 7 | -------------------------------------------------------------------------------- /docker/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2018, go-dockerclient authors 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /docker/change.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Copyright 2014 go-dockerclient authors. All rights reserved. 5 | // Use of this source code is governed by a BSD-style 6 | // license that can be found in the LICENSE file. 7 | 8 | package docker 9 | 10 | import "fmt" 11 | 12 | // ChangeType is a type for constants indicating the type of change 13 | // in a container 14 | type ChangeType int 15 | 16 | const ( 17 | // ChangeModify is the ChangeType for container modifications 18 | ChangeModify ChangeType = iota 19 | 20 | // ChangeAdd is the ChangeType for additions to a container 21 | ChangeAdd 22 | 23 | // ChangeDelete is the ChangeType for deletions from a container 24 | ChangeDelete 25 | ) 26 | 27 | // Change represents a change in a container. 28 | // 29 | // See https://goo.gl/Wo0JJp for more details. 30 | type Change struct { 31 | Path string 32 | Kind ChangeType 33 | } 34 | 35 | func (change *Change) String() string { 36 | var kind string 37 | switch change.Kind { 38 | case ChangeModify: 39 | kind = "C" 40 | case ChangeAdd: 41 | kind = "A" 42 | case ChangeDelete: 43 | kind = "D" 44 | } 45 | return fmt.Sprintf("%s %s", kind, change.Path) 46 | } 47 | -------------------------------------------------------------------------------- /docker/client_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Copyright 2016 go-dockerclient authors. All rights reserved. 5 | // Use of this source code is governed by a BSD-style 6 | // license that can be found in the LICENSE file. 7 | 8 | //go:build !windows 9 | // +build !windows 10 | 11 | package docker 12 | 13 | import ( 14 | "context" 15 | "net" 16 | "net/http" 17 | ) 18 | 19 | // initializeNativeClient initializes the native Unix domain socket client on 20 | // Unix-style operating systems 21 | func (c *Client) initializeNativeClient(trFunc func() *http.Transport) { 22 | if c.endpointURL.Scheme != unixProtocol { 23 | return 24 | } 25 | sockPath := c.endpointURL.Path 26 | 27 | tr := trFunc() 28 | 29 | tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { 30 | return c.Dialer.Dial(unixProtocol, sockPath) 31 | } 32 | c.HTTPClient.Transport = tr 33 | } 34 | -------------------------------------------------------------------------------- /docker/client_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Copyright 2016 go-dockerclient authors. All rights reserved. 5 | // Use of this source code is governed by a BSD-style 6 | // license that can be found in the LICENSE file. 7 | 8 | //go:build windows 9 | // +build windows 10 | 11 | package docker 12 | 13 | import ( 14 | "context" 15 | "net" 16 | "net/http" 17 | "time" 18 | 19 | "github.com/Microsoft/go-winio" 20 | ) 21 | 22 | const namedPipeConnectTimeout = 2 * time.Second 23 | 24 | type pipeDialer struct { 25 | dialFunc func(network, addr string) (net.Conn, error) 26 | } 27 | 28 | func (p pipeDialer) Dial(network, address string) (net.Conn, error) { 29 | return p.dialFunc(network, address) 30 | } 31 | 32 | // initializeNativeClient initializes the native Named Pipe client for Windows 33 | func (c *Client) initializeNativeClient(trFunc func() *http.Transport) { 34 | if c.endpointURL.Scheme != namedPipeProtocol { 35 | return 36 | } 37 | namedPipePath := c.endpointURL.Path 38 | dialFunc := func(network, addr string) (net.Conn, error) { 39 | timeout := namedPipeConnectTimeout 40 | return winio.DialPipe(namedPipePath, &timeout) 41 | } 42 | tr := trFunc() 43 | tr.Dial = dialFunc 44 | tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { 45 | return dialFunc(network, addr) 46 | } 47 | c.Dialer = &pipeDialer{dialFunc} 48 | c.HTTPClient.Transport = tr 49 | } 50 | -------------------------------------------------------------------------------- /docker/distribution.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Copyright 2017 go-dockerclient authors. All rights reserved. 5 | // Use of this source code is governed by a BSD-style 6 | // license that can be found in the LICENSE file. 7 | 8 | package docker 9 | 10 | import ( 11 | "encoding/json" 12 | 13 | "github.com/ory/dockertest/v3/docker/types/registry" 14 | ) 15 | 16 | // InspectDistribution returns image digest and platform information by contacting the registry 17 | func (c *Client) InspectDistribution(name string) (*registry.DistributionInspect, error) { 18 | path := "/distribution/" + name + "/json" 19 | resp, err := c.do("GET", path, doOptions{}) 20 | if err != nil { 21 | return nil, err 22 | } 23 | defer resp.Body.Close() 24 | var distributionInspect registry.DistributionInspect 25 | if err := json.NewDecoder(resp.Body).Decode(&distributionInspect); err != nil { 26 | return nil, err 27 | } 28 | return &distributionInspect, nil 29 | } 30 | -------------------------------------------------------------------------------- /docker/opts/env.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package opts 5 | 6 | import ( 7 | "fmt" 8 | "os" 9 | "runtime" 10 | "strings" 11 | ) 12 | 13 | // ValidateEnv validates an environment variable and returns it. 14 | // If no value is specified, it returns the current value using os.Getenv. 15 | // 16 | // As on ParseEnvFile and related to #16585, environment variable names 17 | // are not validate what so ever, it's up to application inside docker 18 | // to validate them or not. 19 | // 20 | // The only validation here is to check if name is empty, per #25099 21 | func ValidateEnv(val string) (string, error) { 22 | arr := strings.Split(val, "=") 23 | if arr[0] == "" { 24 | return "", fmt.Errorf("invalid environment variable: %s", val) 25 | } 26 | if len(arr) > 1 { 27 | return val, nil 28 | } 29 | if !doesEnvExist(val) { 30 | return val, nil 31 | } 32 | return fmt.Sprintf("%s=%s", val, os.Getenv(val)), nil 33 | } 34 | 35 | func doesEnvExist(name string) bool { 36 | for _, entry := range os.Environ() { 37 | parts := strings.SplitN(entry, "=", 2) 38 | if runtime.GOOS == "windows" { 39 | // Environment variable are case-insensitive on Windows. PaTh, path and PATH are equivalent. 40 | if strings.EqualFold(parts[0], name) { 41 | return true 42 | } 43 | } 44 | if parts[0] == name { 45 | return true 46 | } 47 | } 48 | return false 49 | } 50 | -------------------------------------------------------------------------------- /docker/opts/hosts_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | // +build !windows 6 | 7 | package opts 8 | 9 | import "fmt" 10 | 11 | // DefaultHost constant defines the default host string used by docker on other hosts than Windows 12 | var DefaultHost = fmt.Sprintf("unix://%s", DefaultUnixSocket) 13 | -------------------------------------------------------------------------------- /docker/opts/hosts_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package opts 5 | 6 | // DefaultHost constant defines the default host string used by docker on Windows 7 | var DefaultHost = "npipe://" + DefaultNamedPipe 8 | -------------------------------------------------------------------------------- /docker/opts/ip.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package opts 5 | 6 | import ( 7 | "fmt" 8 | "net" 9 | ) 10 | 11 | // IPOpt holds an IP. It is used to store values from CLI flags. 12 | type IPOpt struct { 13 | *net.IP 14 | } 15 | 16 | // NewIPOpt creates a new IPOpt from a reference net.IP and a 17 | // string representation of an IP. If the string is not a valid 18 | // IP it will fallback to the specified reference. 19 | func NewIPOpt(ref *net.IP, defaultVal string) *IPOpt { 20 | o := &IPOpt{ 21 | IP: ref, 22 | } 23 | o.Set(defaultVal) 24 | return o 25 | } 26 | 27 | // Set sets an IPv4 or IPv6 address from a given string. If the given 28 | // string is not parsable as an IP address it returns an error. 29 | func (o *IPOpt) Set(val string) error { 30 | ip := net.ParseIP(val) 31 | if ip == nil { 32 | return fmt.Errorf("%s is not an ip address", val) 33 | } 34 | *o.IP = ip 35 | return nil 36 | } 37 | 38 | // String returns the IP address stored in the IPOpt. If stored IP is a 39 | // nil pointer, it returns an empty string. 40 | func (o *IPOpt) String() string { 41 | if *o.IP == nil { 42 | return "" 43 | } 44 | return o.IP.String() 45 | } 46 | 47 | // Type returns the type of the option 48 | func (o *IPOpt) Type() string { 49 | return "ip" 50 | } 51 | -------------------------------------------------------------------------------- /docker/opts/opts_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | // +build !windows 6 | 7 | package opts 8 | 9 | // DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. dockerd -H tcp://:8080 10 | const DefaultHTTPHost = "localhost" 11 | -------------------------------------------------------------------------------- /docker/opts/opts_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package opts 5 | 6 | // TODO Windows. Identify bug in GOLang 1.5.1+ and/or Windows Server 2016 TP5. 7 | // @jhowardmsft, @swernli. 8 | // 9 | // On Windows, this mitigates a problem with the default options of running 10 | // a docker client against a local docker daemon on TP5. 11 | // 12 | // What was found that if the default host is "localhost", even if the client 13 | // (and daemon as this is local) is not physically on a network, and the DNS 14 | // cache is flushed (ipconfig /flushdns), then the client will pause for 15 | // exactly one second when connecting to the daemon for calls. For example 16 | // using docker run windowsservercore cmd, the CLI will send a create followed 17 | // by an attach. You see the delay between the attach finishing and the attach 18 | // being seen by the daemon. 19 | // 20 | // Here's some daemon debug logs with additional debug spew put in. The 21 | // AfterWriteJSON log is the very last thing the daemon does as part of the 22 | // create call. The POST /attach is the second CLI call. Notice the second 23 | // time gap. 24 | // 25 | // time="2015-11-06T13:38:37.259627400-08:00" level=debug msg="After createRootfs" 26 | // time="2015-11-06T13:38:37.263626300-08:00" level=debug msg="After setHostConfig" 27 | // time="2015-11-06T13:38:37.267631200-08:00" level=debug msg="before createContainerPl...." 28 | // time="2015-11-06T13:38:37.271629500-08:00" level=debug msg=ToDiskLocking.... 29 | // time="2015-11-06T13:38:37.275643200-08:00" level=debug msg="loggin event...." 30 | // time="2015-11-06T13:38:37.277627600-08:00" level=debug msg="logged event...." 31 | // time="2015-11-06T13:38:37.279631800-08:00" level=debug msg="In defer func" 32 | // time="2015-11-06T13:38:37.282628100-08:00" level=debug msg="After daemon.create" 33 | // time="2015-11-06T13:38:37.286651700-08:00" level=debug msg="return 2" 34 | // time="2015-11-06T13:38:37.289629500-08:00" level=debug msg="Returned from daemon.ContainerCreate" 35 | // time="2015-11-06T13:38:37.311629100-08:00" level=debug msg="After WriteJSON" 36 | // ... 1 second gap here.... 37 | // time="2015-11-06T13:38:38.317866200-08:00" level=debug msg="Calling POST /v1.22/containers/984758282b842f779e805664b2c95d563adc9a979c8a3973e68c807843ee4757/attach" 38 | // time="2015-11-06T13:38:38.326882500-08:00" level=info msg="POST /v1.22/containers/984758282b842f779e805664b2c95d563adc9a979c8a3973e68c807843ee4757/attach?stderr=1&stdin=1&stdout=1&stream=1" 39 | // 40 | // We suspect this is either a bug introduced in GOLang 1.5.1, or that a change 41 | // in GOLang 1.5.1 (from 1.4.3) is exposing a bug in Windows. In theory, 42 | // the Windows networking stack is supposed to resolve "localhost" internally, 43 | // without hitting DNS, or even reading the hosts file (which is why localhost 44 | // is commented out in the hosts file on Windows). 45 | // 46 | // We have validated that working around this using the actual IPv4 localhost 47 | // address does not cause the delay. 48 | // 49 | // This does not occur with the docker client built with 1.4.3 on the same 50 | // Windows build, regardless of whether the daemon is built using 1.5.1 51 | // or 1.4.3. It does not occur on Linux. We also verified we see the same thing 52 | // on a cross-compiled Windows binary (from Linux). 53 | // 54 | // Final note: This is a mitigation, not a 'real' fix. It is still susceptible 55 | // to the delay if a user were to do 'docker run -H=tcp://localhost:2375...' 56 | // explicitly. 57 | 58 | // DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. dockerd -H tcp://:8080 59 | const DefaultHTTPHost = "127.0.0.1" 60 | -------------------------------------------------------------------------------- /docker/opts/quotedstring.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package opts 5 | 6 | // QuotedString is a string that may have extra quotes around the value. The 7 | // quotes are stripped from the value. 8 | type QuotedString struct { 9 | value *string 10 | } 11 | 12 | // Set sets a new value 13 | func (s *QuotedString) Set(val string) error { 14 | *s.value = trimQuotes(val) 15 | return nil 16 | } 17 | 18 | // Type returns the type of the value 19 | func (s *QuotedString) Type() string { 20 | return "string" 21 | } 22 | 23 | func (s *QuotedString) String() string { 24 | return *s.value 25 | } 26 | 27 | func trimQuotes(value string) string { 28 | lastIndex := len(value) - 1 29 | for _, char := range []byte{'\'', '"'} { 30 | if value[0] == char && value[lastIndex] == char { 31 | return value[1:lastIndex] 32 | } 33 | } 34 | return value 35 | } 36 | 37 | // NewQuotedString returns a new quoted string option 38 | func NewQuotedString(value *string) *QuotedString { 39 | return &QuotedString{value: value} 40 | } 41 | -------------------------------------------------------------------------------- /docker/opts/runtime.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package opts 5 | 6 | import ( 7 | "fmt" 8 | "strings" 9 | 10 | "github.com/ory/dockertest/v3/docker/types" 11 | ) 12 | 13 | // RuntimeOpt defines a map of Runtimes 14 | type RuntimeOpt struct { 15 | name string 16 | stockRuntimeName string 17 | values *map[string]types.Runtime 18 | } 19 | 20 | // NewNamedRuntimeOpt creates a new RuntimeOpt 21 | func NewNamedRuntimeOpt(name string, ref *map[string]types.Runtime, stockRuntime string) *RuntimeOpt { 22 | if ref == nil { 23 | ref = &map[string]types.Runtime{} 24 | } 25 | return &RuntimeOpt{name: name, values: ref, stockRuntimeName: stockRuntime} 26 | } 27 | 28 | // Name returns the name of the NamedListOpts in the configuration. 29 | func (o *RuntimeOpt) Name() string { 30 | return o.name 31 | } 32 | 33 | // Set validates and updates the list of Runtimes 34 | func (o *RuntimeOpt) Set(val string) error { 35 | parts := strings.SplitN(val, "=", 2) 36 | if len(parts) != 2 { 37 | return fmt.Errorf("invalid runtime argument: %s", val) 38 | } 39 | 40 | parts[0] = strings.TrimSpace(parts[0]) 41 | parts[1] = strings.TrimSpace(parts[1]) 42 | if parts[0] == "" || parts[1] == "" { 43 | return fmt.Errorf("invalid runtime argument: %s", val) 44 | } 45 | 46 | parts[0] = strings.ToLower(parts[0]) 47 | if parts[0] == o.stockRuntimeName { 48 | return fmt.Errorf("runtime name '%s' is reserved", o.stockRuntimeName) 49 | } 50 | 51 | if _, ok := (*o.values)[parts[0]]; ok { 52 | return fmt.Errorf("runtime '%s' was already defined", parts[0]) 53 | } 54 | 55 | (*o.values)[parts[0]] = types.Runtime{Path: parts[1]} 56 | 57 | return nil 58 | } 59 | 60 | // String returns Runtime values as a string. 61 | func (o *RuntimeOpt) String() string { 62 | var out []string 63 | for k := range *o.values { 64 | out = append(out, k) 65 | } 66 | 67 | return fmt.Sprintf("%v", out) 68 | } 69 | 70 | // GetMap returns a map of Runtimes (name: path) 71 | func (o *RuntimeOpt) GetMap() map[string]types.Runtime { 72 | if o.values != nil { 73 | return *o.values 74 | } 75 | 76 | return map[string]types.Runtime{} 77 | } 78 | 79 | // Type returns the type of the option 80 | func (o *RuntimeOpt) Type() string { 81 | return "runtime" 82 | } 83 | -------------------------------------------------------------------------------- /docker/opts/ulimit.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package opts 5 | 6 | import ( 7 | "fmt" 8 | 9 | "github.com/docker/go-units" 10 | ) 11 | 12 | // UlimitOpt defines a map of Ulimits 13 | type UlimitOpt struct { 14 | values *map[string]*units.Ulimit 15 | } 16 | 17 | // NewUlimitOpt creates a new UlimitOpt 18 | func NewUlimitOpt(ref *map[string]*units.Ulimit) *UlimitOpt { 19 | if ref == nil { 20 | ref = &map[string]*units.Ulimit{} 21 | } 22 | return &UlimitOpt{ref} 23 | } 24 | 25 | // Set validates a Ulimit and sets its name as a key in UlimitOpt 26 | func (o *UlimitOpt) Set(val string) error { 27 | l, err := units.ParseUlimit(val) 28 | if err != nil { 29 | return err 30 | } 31 | 32 | (*o.values)[l.Name] = l 33 | 34 | return nil 35 | } 36 | 37 | // String returns Ulimit values as a string. 38 | func (o *UlimitOpt) String() string { 39 | var out []string 40 | for _, v := range *o.values { 41 | out = append(out, v.String()) 42 | } 43 | 44 | return fmt.Sprintf("%v", out) 45 | } 46 | 47 | // GetList returns a slice of pointers to Ulimits. 48 | func (o *UlimitOpt) GetList() []*units.Ulimit { 49 | var ulimits []*units.Ulimit 50 | for _, v := range *o.values { 51 | ulimits = append(ulimits, v) 52 | } 53 | 54 | return ulimits 55 | } 56 | 57 | // Type returns the option type 58 | func (o *UlimitOpt) Type() string { 59 | return "ulimit" 60 | } 61 | 62 | // NamedUlimitOpt defines a named map of Ulimits 63 | type NamedUlimitOpt struct { 64 | name string 65 | UlimitOpt 66 | } 67 | 68 | var _ NamedOption = &NamedUlimitOpt{} 69 | 70 | // NewNamedUlimitOpt creates a new NamedUlimitOpt 71 | func NewNamedUlimitOpt(name string, ref *map[string]*units.Ulimit) *NamedUlimitOpt { 72 | if ref == nil { 73 | ref = &map[string]*units.Ulimit{} 74 | } 75 | return &NamedUlimitOpt{ 76 | name: name, 77 | UlimitOpt: *NewUlimitOpt(ref), 78 | } 79 | } 80 | 81 | // Name returns the option name 82 | func (o *NamedUlimitOpt) Name() string { 83 | return o.name 84 | } 85 | -------------------------------------------------------------------------------- /docker/pkg/README.md: -------------------------------------------------------------------------------- 1 | pkg/ is a collection of utility packages used by the Moby project without being 2 | specific to its internals. 3 | 4 | Utility packages are kept separate from the moby core codebase to keep it as 5 | small and concise as possible. If some utilities grow larger and their APIs 6 | stabilize, they may be moved to their own repository under the Moby 7 | organization, to facilitate re-use by other projects. However that is not the 8 | priority. 9 | 10 | The directory `pkg` is named after the same directory in the camlistore project. 11 | Since Brad is a core Go maintainer, we thought it made sense to copy his methods 12 | for organizing Go code :) Thanks Brad! 13 | 14 | Because utility packages are small and neatly separated from the rest of the 15 | codebase, they are a good place to start for aspiring maintainers and 16 | contributors. Get in touch if you want to help maintain them! 17 | -------------------------------------------------------------------------------- /docker/pkg/archive/README.md: -------------------------------------------------------------------------------- 1 | This code provides helper functions for dealing with archive files. 2 | -------------------------------------------------------------------------------- /docker/pkg/archive/archive_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package archive // import "github.com/ory/dockertest/v3/docker/pkg/archive" 5 | 6 | import ( 7 | "archive/tar" 8 | "os" 9 | "path/filepath" 10 | "strings" 11 | 12 | "github.com/ory/dockertest/v3/docker/pkg/system" 13 | "golang.org/x/sys/unix" 14 | ) 15 | 16 | func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter { 17 | if format == OverlayWhiteoutFormat { 18 | return overlayWhiteoutConverter{} 19 | } 20 | return nil 21 | } 22 | 23 | type overlayWhiteoutConverter struct{} 24 | 25 | func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os.FileInfo) (wo *tar.Header, err error) { 26 | // convert whiteouts to AUFS format 27 | if fi.Mode()&os.ModeCharDevice != 0 && hdr.Devmajor == 0 && hdr.Devminor == 0 { 28 | // we just rename the file and make it normal 29 | dir, filename := filepath.Split(hdr.Name) 30 | hdr.Name = filepath.Join(dir, WhiteoutPrefix+filename) 31 | hdr.Mode = 0600 32 | hdr.Typeflag = tar.TypeReg 33 | hdr.Size = 0 34 | } 35 | 36 | if fi.Mode()&os.ModeDir != 0 { 37 | // convert opaque dirs to AUFS format by writing an empty file with the prefix 38 | opaque, err := system.Lgetxattr(path, "trusted.overlay.opaque") 39 | if err != nil { 40 | return nil, err 41 | } 42 | if len(opaque) == 1 && opaque[0] == 'y' { 43 | if hdr.Xattrs != nil { 44 | delete(hdr.Xattrs, "trusted.overlay.opaque") 45 | } 46 | 47 | // create a header for the whiteout file 48 | // it should inherit some properties from the parent, but be a regular file 49 | wo = &tar.Header{ 50 | Typeflag: tar.TypeReg, 51 | Mode: hdr.Mode & int64(os.ModePerm), 52 | Name: filepath.Join(hdr.Name, WhiteoutOpaqueDir), 53 | Size: 0, 54 | Uid: hdr.Uid, 55 | Uname: hdr.Uname, 56 | Gid: hdr.Gid, 57 | Gname: hdr.Gname, 58 | AccessTime: hdr.AccessTime, 59 | ChangeTime: hdr.ChangeTime, 60 | } 61 | } 62 | } 63 | 64 | return 65 | } 66 | 67 | func (overlayWhiteoutConverter) ConvertRead(hdr *tar.Header, path string) (bool, error) { 68 | base := filepath.Base(path) 69 | dir := filepath.Dir(path) 70 | 71 | // if a directory is marked as opaque by the AUFS special file, we need to translate that to overlay 72 | if base == WhiteoutOpaqueDir { 73 | err := unix.Setxattr(dir, "trusted.overlay.opaque", []byte{'y'}, 0) 74 | // don't write the file itself 75 | return false, err 76 | } 77 | 78 | // if a file was deleted and we are using overlay, we need to create a character device 79 | if strings.HasPrefix(base, WhiteoutPrefix) { 80 | originalBase := base[len(WhiteoutPrefix):] 81 | originalPath := filepath.Join(dir, originalBase) 82 | 83 | if err := unix.Mknod(originalPath, unix.S_IFCHR, 0); err != nil { 84 | return false, err 85 | } 86 | if err := os.Chown(originalPath, hdr.Uid, hdr.Gid); err != nil { 87 | return false, err 88 | } 89 | 90 | // don't write the file itself 91 | return false, nil 92 | } 93 | 94 | return true, nil 95 | } 96 | -------------------------------------------------------------------------------- /docker/pkg/archive/archive_other.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !linux 5 | // +build !linux 6 | 7 | package archive // import "github.com/ory/dockertest/v3/docker/pkg/archive" 8 | 9 | func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter { 10 | return nil 11 | } 12 | -------------------------------------------------------------------------------- /docker/pkg/archive/archive_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package archive // import "github.com/ory/dockertest/v3/docker/pkg/archive" 5 | 6 | import ( 7 | "archive/tar" 8 | "fmt" 9 | "os" 10 | "path/filepath" 11 | "strings" 12 | 13 | "github.com/ory/dockertest/v3/docker/pkg/idtools" 14 | "github.com/ory/dockertest/v3/docker/pkg/longpath" 15 | ) 16 | 17 | // fixVolumePathPrefix does platform specific processing to ensure that if 18 | // the path being passed in is not in a volume path format, convert it to one. 19 | func fixVolumePathPrefix(srcPath string) string { 20 | return longpath.AddPrefix(srcPath) 21 | } 22 | 23 | // getWalkRoot calculates the root path when performing a TarWithOptions. 24 | // We use a separate function as this is platform specific. 25 | func getWalkRoot(srcPath string, include string) string { 26 | return filepath.Join(srcPath, include) 27 | } 28 | 29 | // CanonicalTarNameForPath returns platform-specific filepath 30 | // to canonical posix-style path for tar archival. p is relative 31 | // path. 32 | func CanonicalTarNameForPath(p string) (string, error) { 33 | // windows: convert windows style relative path with backslashes 34 | // into forward slashes. Since windows does not allow '/' or '\' 35 | // in file names, it is mostly safe to replace however we must 36 | // check just in case 37 | if strings.Contains(p, "/") { 38 | return "", fmt.Errorf("Windows path contains forward slash: %s", p) 39 | } 40 | return strings.Replace(p, string(os.PathSeparator), "/", -1), nil 41 | 42 | } 43 | 44 | // chmodTarEntry is used to adjust the file permissions used in tar header based 45 | // on the platform the archival is done. 46 | func chmodTarEntry(perm os.FileMode) os.FileMode { 47 | //perm &= 0755 // this 0-ed out tar flags (like link, regular file, directory marker etc.) 48 | permPart := perm & os.ModePerm 49 | noPermPart := perm &^ os.ModePerm 50 | // Add the x bit: make everything +x from windows 51 | permPart |= 0111 52 | permPart &= 0755 53 | 54 | return noPermPart | permPart 55 | } 56 | 57 | func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat interface{}) (err error) { 58 | // do nothing. no notion of Rdev, Nlink in stat on Windows 59 | return 60 | } 61 | 62 | func getInodeFromStat(stat interface{}) (inode uint64, err error) { 63 | // do nothing. no notion of Inode in stat on Windows 64 | return 65 | } 66 | 67 | // handleTarTypeBlockCharFifo is an OS-specific helper function used by 68 | // createTarFile to handle the following types of header: Block; Char; Fifo 69 | func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error { 70 | return nil 71 | } 72 | 73 | func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error { 74 | return nil 75 | } 76 | 77 | func getFileUIDGID(stat interface{}) (idtools.IDPair, error) { 78 | // no notion of file ownership mapping yet on Windows 79 | return idtools.IDPair{0, 0}, nil 80 | } 81 | -------------------------------------------------------------------------------- /docker/pkg/archive/changes_other.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !linux 5 | // +build !linux 6 | 7 | package archive // import "github.com/ory/dockertest/v3/docker/pkg/archive" 8 | 9 | import ( 10 | "fmt" 11 | "os" 12 | "path/filepath" 13 | "runtime" 14 | "strings" 15 | 16 | "github.com/ory/dockertest/v3/docker/pkg/system" 17 | ) 18 | 19 | func collectFileInfoForChanges(oldDir, newDir string) (*FileInfo, *FileInfo, error) { 20 | var ( 21 | oldRoot, newRoot *FileInfo 22 | err1, err2 error 23 | errs = make(chan error, 2) 24 | ) 25 | go func() { 26 | oldRoot, err1 = collectFileInfo(oldDir) 27 | errs <- err1 28 | }() 29 | go func() { 30 | newRoot, err2 = collectFileInfo(newDir) 31 | errs <- err2 32 | }() 33 | 34 | // block until both routines have returned 35 | for i := 0; i < 2; i++ { 36 | if err := <-errs; err != nil { 37 | return nil, nil, err 38 | } 39 | } 40 | 41 | return oldRoot, newRoot, nil 42 | } 43 | 44 | func collectFileInfo(sourceDir string) (*FileInfo, error) { 45 | root := newRootFileInfo() 46 | 47 | err := filepath.Walk(sourceDir, func(path string, f os.FileInfo, err error) error { 48 | if err != nil { 49 | return err 50 | } 51 | 52 | // Rebase path 53 | relPath, err := filepath.Rel(sourceDir, path) 54 | if err != nil { 55 | return err 56 | } 57 | 58 | // As this runs on the daemon side, file paths are OS specific. 59 | relPath = filepath.Join(string(os.PathSeparator), relPath) 60 | 61 | // See https://github.com/golang/go/issues/9168 - bug in filepath.Join. 62 | // Temporary workaround. If the returned path starts with two backslashes, 63 | // trim it down to a single backslash. Only relevant on Windows. 64 | if runtime.GOOS == "windows" { 65 | if strings.HasPrefix(relPath, `\\`) { 66 | relPath = relPath[1:] 67 | } 68 | } 69 | 70 | if relPath == string(os.PathSeparator) { 71 | return nil 72 | } 73 | 74 | parent := root.LookUp(filepath.Dir(relPath)) 75 | if parent == nil { 76 | return fmt.Errorf("collectFileInfo: Unexpectedly no parent for %s", relPath) 77 | } 78 | 79 | info := &FileInfo{ 80 | name: filepath.Base(relPath), 81 | children: make(map[string]*FileInfo), 82 | parent: parent, 83 | } 84 | 85 | s, err := system.Lstat(path) 86 | if err != nil { 87 | return err 88 | } 89 | info.stat = s 90 | 91 | info.capability, _ = system.Lgetxattr(path, "security.capability") 92 | 93 | parent.children[info.name] = info 94 | 95 | return nil 96 | }) 97 | if err != nil { 98 | return nil, err 99 | } 100 | return root, nil 101 | } 102 | -------------------------------------------------------------------------------- /docker/pkg/archive/changes_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | // +build !windows 6 | 7 | package archive // import "github.com/ory/dockertest/v3/docker/pkg/archive" 8 | 9 | import ( 10 | "os" 11 | "syscall" 12 | 13 | "github.com/ory/dockertest/v3/docker/pkg/system" 14 | "golang.org/x/sys/unix" 15 | ) 16 | 17 | func statDifferent(oldStat *system.StatT, newStat *system.StatT) bool { 18 | // Don't look at size for dirs, its not a good measure of change 19 | if oldStat.Mode() != newStat.Mode() || 20 | oldStat.UID() != newStat.UID() || 21 | oldStat.GID() != newStat.GID() || 22 | oldStat.Rdev() != newStat.Rdev() || 23 | // Don't look at size for dirs, its not a good measure of change 24 | (oldStat.Mode()&unix.S_IFDIR != unix.S_IFDIR && 25 | (!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) || (oldStat.Size() != newStat.Size()))) { 26 | return true 27 | } 28 | return false 29 | } 30 | 31 | func (info *FileInfo) isDir() bool { 32 | return info.parent == nil || info.stat.Mode()&unix.S_IFDIR != 0 33 | } 34 | 35 | func getIno(fi os.FileInfo) uint64 { 36 | return fi.Sys().(*syscall.Stat_t).Ino 37 | } 38 | 39 | func hasHardlinks(fi os.FileInfo) bool { 40 | return fi.Sys().(*syscall.Stat_t).Nlink > 1 41 | } 42 | -------------------------------------------------------------------------------- /docker/pkg/archive/changes_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package archive // import "github.com/ory/dockertest/v3/docker/pkg/archive" 5 | 6 | import ( 7 | "os" 8 | 9 | "github.com/ory/dockertest/v3/docker/pkg/system" 10 | ) 11 | 12 | func statDifferent(oldStat *system.StatT, newStat *system.StatT) bool { 13 | 14 | // Don't look at size for dirs, its not a good measure of change 15 | if oldStat.Mtim() != newStat.Mtim() || 16 | oldStat.Mode() != newStat.Mode() || 17 | oldStat.Size() != newStat.Size() && !oldStat.Mode().IsDir() { 18 | return true 19 | } 20 | return false 21 | } 22 | 23 | func (info *FileInfo) isDir() bool { 24 | return info.parent == nil || info.stat.Mode().IsDir() 25 | } 26 | 27 | func getIno(fi os.FileInfo) (inode uint64) { 28 | return 29 | } 30 | 31 | func hasHardlinks(fi os.FileInfo) bool { 32 | return false 33 | } 34 | -------------------------------------------------------------------------------- /docker/pkg/archive/copy_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | // +build !windows 6 | 7 | package archive // import "github.com/ory/dockertest/v3/docker/pkg/archive" 8 | 9 | import ( 10 | "path/filepath" 11 | ) 12 | 13 | func normalizePath(path string) string { 14 | return filepath.ToSlash(path) 15 | } 16 | -------------------------------------------------------------------------------- /docker/pkg/archive/copy_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package archive // import "github.com/ory/dockertest/v3/docker/pkg/archive" 5 | 6 | import ( 7 | "path/filepath" 8 | ) 9 | 10 | func normalizePath(path string) string { 11 | return filepath.FromSlash(path) 12 | } 13 | -------------------------------------------------------------------------------- /docker/pkg/archive/example_changes.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build ignore 5 | // +build ignore 6 | 7 | // Simple tool to create an archive stream from an old and new directory 8 | // 9 | // By default it will stream the comparison of two temporary directories with junk files 10 | package main 11 | 12 | import ( 13 | "flag" 14 | "fmt" 15 | "io" 16 | "os" 17 | "path" 18 | 19 | "github.com/ory/dockertest/v3/docker/pkg/archive" 20 | "github.com/sirupsen/logrus" 21 | ) 22 | 23 | var ( 24 | flDebug = flag.Bool("D", false, "debugging output") 25 | flNewDir = flag.String("newdir", "", "") 26 | flOldDir = flag.String("olddir", "", "") 27 | log = logrus.New() 28 | ) 29 | 30 | func main() { 31 | flag.Usage = func() { 32 | fmt.Println("Produce a tar from comparing two directory paths. By default a demo tar is created of around 200 files (including hardlinks)") 33 | fmt.Printf("%s [OPTIONS]\n", os.Args[0]) 34 | flag.PrintDefaults() 35 | } 36 | flag.Parse() 37 | log.Out = os.Stderr 38 | if (len(os.Getenv("DEBUG")) > 0) || *flDebug { 39 | logrus.SetLevel(logrus.DebugLevel) 40 | } 41 | var newDir, oldDir string 42 | 43 | if len(*flNewDir) == 0 { 44 | var err error 45 | newDir, err = os.MkdirTemp("", "docker-test-newDir") 46 | if err != nil { 47 | log.Fatal(err) 48 | } 49 | defer os.RemoveAll(newDir) 50 | if _, err := prepareUntarSourceDirectory(100, newDir, true); err != nil { 51 | log.Fatal(err) 52 | } 53 | } else { 54 | newDir = *flNewDir 55 | } 56 | 57 | if len(*flOldDir) == 0 { 58 | oldDir, err := os.MkdirTemp("", "docker-test-oldDir") 59 | if err != nil { 60 | log.Fatal(err) 61 | } 62 | defer os.RemoveAll(oldDir) 63 | } else { 64 | oldDir = *flOldDir 65 | } 66 | 67 | changes, err := archive.ChangesDirs(newDir, oldDir) 68 | if err != nil { 69 | log.Fatal(err) 70 | } 71 | 72 | a, err := archive.ExportChanges(newDir, changes) 73 | if err != nil { 74 | log.Fatal(err) 75 | } 76 | defer a.Close() 77 | 78 | i, err := io.Copy(os.Stdout, a) 79 | if err != nil && err != io.EOF { 80 | log.Fatal(err) 81 | } 82 | fmt.Fprintf(os.Stderr, "wrote archive of %d bytes", i) 83 | } 84 | 85 | func prepareUntarSourceDirectory(numberOfFiles int, targetPath string, makeLinks bool) (int, error) { 86 | fileData := []byte("fooo") 87 | for n := 0; n < numberOfFiles; n++ { 88 | fileName := fmt.Sprintf("file-%d", n) 89 | if err := os.WriteFile(path.Join(targetPath, fileName), fileData, 0700); err != nil { 90 | return 0, err 91 | } 92 | if makeLinks { 93 | if err := os.Link(path.Join(targetPath, fileName), path.Join(targetPath, fileName+"-link")); err != nil { 94 | return 0, err 95 | } 96 | } 97 | } 98 | totalSize := numberOfFiles * len(fileData) 99 | return totalSize, nil 100 | } 101 | -------------------------------------------------------------------------------- /docker/pkg/archive/testdata/broken.tar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ory/dockertest/8c686a03019f80bbc4dcd2548951b92ff64f12df/docker/pkg/archive/testdata/broken.tar -------------------------------------------------------------------------------- /docker/pkg/archive/time_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package archive // import "github.com/ory/dockertest/v3/docker/pkg/archive" 5 | 6 | import ( 7 | "syscall" 8 | "time" 9 | ) 10 | 11 | func timeToTimespec(time time.Time) (ts syscall.Timespec) { 12 | if time.IsZero() { 13 | // Return UTIME_OMIT special value 14 | ts.Sec = 0 15 | ts.Nsec = ((1 << 30) - 2) 16 | return 17 | } 18 | return syscall.NsecToTimespec(time.UnixNano()) 19 | } 20 | -------------------------------------------------------------------------------- /docker/pkg/archive/time_unsupported.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !linux 5 | // +build !linux 6 | 7 | package archive // import "github.com/ory/dockertest/v3/docker/pkg/archive" 8 | 9 | import ( 10 | "syscall" 11 | "time" 12 | ) 13 | 14 | func timeToTimespec(time time.Time) (ts syscall.Timespec) { 15 | nsec := int64(0) 16 | if !time.IsZero() { 17 | nsec = time.UnixNano() 18 | } 19 | return syscall.NsecToTimespec(nsec) 20 | } 21 | -------------------------------------------------------------------------------- /docker/pkg/archive/whiteouts.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package archive // import "github.com/ory/dockertest/v3/docker/pkg/archive" 5 | 6 | // Whiteouts are files with a special meaning for the layered filesystem. 7 | // Docker uses AUFS whiteout files inside exported archives. In other 8 | // filesystems these files are generated/handled on tar creation/extraction. 9 | 10 | // WhiteoutPrefix prefix means file is a whiteout. If this is followed by a 11 | // filename this means that file has been removed from the base layer. 12 | const WhiteoutPrefix = ".wh." 13 | 14 | // WhiteoutMetaPrefix prefix means whiteout has a special meaning and is not 15 | // for removing an actual file. Normally these files are excluded from exported 16 | // archives. 17 | const WhiteoutMetaPrefix = WhiteoutPrefix + WhiteoutPrefix 18 | 19 | // WhiteoutLinkDir is a directory AUFS uses for storing hardlink links to other 20 | // layers. Normally these should not go into exported archives and all changed 21 | // hardlinks should be copied to the top layer. 22 | const WhiteoutLinkDir = WhiteoutMetaPrefix + "plnk" 23 | 24 | // WhiteoutOpaqueDir file means directory has been made opaque - meaning 25 | // readdir calls to this directory do not follow to lower layers. 26 | const WhiteoutOpaqueDir = WhiteoutMetaPrefix + ".opq" 27 | -------------------------------------------------------------------------------- /docker/pkg/archive/wrap.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package archive // import "github.com/ory/dockertest/v3/docker/pkg/archive" 5 | 6 | import ( 7 | "archive/tar" 8 | "bytes" 9 | "io" 10 | ) 11 | 12 | // Generate generates a new archive from the content provided 13 | // as input. 14 | // 15 | // `files` is a sequence of path/content pairs. A new file is 16 | // added to the archive for each pair. 17 | // If the last pair is incomplete, the file is created with an 18 | // empty content. For example: 19 | // 20 | // Generate("foo.txt", "hello world", "emptyfile") 21 | // 22 | // The above call will return an archive with 2 files: 23 | // - ./foo.txt with content "hello world" 24 | // - ./empty with empty content 25 | // 26 | // FIXME: stream content instead of buffering 27 | // FIXME: specify permissions and other archive metadata 28 | func Generate(input ...string) (io.Reader, error) { 29 | files := parseStringPairs(input...) 30 | buf := new(bytes.Buffer) 31 | tw := tar.NewWriter(buf) 32 | for _, file := range files { 33 | name, content := file[0], file[1] 34 | hdr := &tar.Header{ 35 | Name: name, 36 | Size: int64(len(content)), 37 | } 38 | if err := tw.WriteHeader(hdr); err != nil { 39 | return nil, err 40 | } 41 | if _, err := tw.Write([]byte(content)); err != nil { 42 | return nil, err 43 | } 44 | } 45 | if err := tw.Close(); err != nil { 46 | return nil, err 47 | } 48 | return buf, nil 49 | } 50 | 51 | func parseStringPairs(input ...string) (output [][2]string) { 52 | output = make([][2]string, 0, len(input)/2+1) 53 | for i := 0; i < len(input); i += 2 { 54 | var pair [2]string 55 | pair[0] = input[i] 56 | if i+1 < len(input) { 57 | pair[1] = input[i+1] 58 | } 59 | output = append(output, pair) 60 | } 61 | return 62 | } 63 | -------------------------------------------------------------------------------- /docker/pkg/fileutils/fileutils_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package fileutils // import "github.com/ory/dockertest/v3/docker/pkg/fileutils" 5 | 6 | import ( 7 | "os" 8 | "os/exec" 9 | "strconv" 10 | "strings" 11 | ) 12 | 13 | // GetTotalUsedFds returns the number of used File Descriptors by 14 | // executing `lsof -p PID` 15 | func GetTotalUsedFds() int { 16 | pid := os.Getpid() 17 | 18 | cmd := exec.Command("lsof", "-p", strconv.Itoa(pid)) 19 | 20 | output, err := cmd.CombinedOutput() 21 | if err != nil { 22 | return -1 23 | } 24 | 25 | outputStr := strings.TrimSpace(string(output)) 26 | 27 | fds := strings.Split(outputStr, "\n") 28 | 29 | return len(fds) - 1 30 | } 31 | -------------------------------------------------------------------------------- /docker/pkg/fileutils/fileutils_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build linux || freebsd 5 | // +build linux freebsd 6 | 7 | package fileutils // import "github.com/ory/dockertest/v3/docker/pkg/fileutils" 8 | 9 | import ( 10 | "fmt" 11 | "os" 12 | 13 | "github.com/sirupsen/logrus" 14 | ) 15 | 16 | // GetTotalUsedFds Returns the number of used File Descriptors by 17 | // reading it via /proc filesystem. 18 | func GetTotalUsedFds() int { 19 | if fds, err := os.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil { 20 | logrus.Errorf("Error opening /proc/%d/fd: %s", os.Getpid(), err) 21 | } else { 22 | return len(fds) 23 | } 24 | return -1 25 | } 26 | -------------------------------------------------------------------------------- /docker/pkg/fileutils/fileutils_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package fileutils // import "github.com/ory/dockertest/v3/docker/pkg/fileutils" 5 | 6 | // GetTotalUsedFds Returns the number of used File Descriptors. Not supported 7 | // on Windows. 8 | func GetTotalUsedFds() int { 9 | return -1 10 | } 11 | -------------------------------------------------------------------------------- /docker/pkg/homedir/homedir_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package homedir // import "github.com/ory/dockertest/v3/docker/pkg/homedir" 5 | 6 | import ( 7 | "os" 8 | 9 | "github.com/ory/dockertest/v3/docker/pkg/idtools" 10 | ) 11 | 12 | // GetStatic returns the home directory for the current user without calling 13 | // os/user.Current(). This is useful for static-linked binary on glibc-based 14 | // system, because a call to os/user.Current() in a static binary leads to 15 | // segfault due to a glibc issue that won't be fixed in a short term. 16 | // (#29344, golang/go#13470, https://sourceware.org/bugzilla/show_bug.cgi?id=19341) 17 | func GetStatic() (string, error) { 18 | uid := os.Getuid() 19 | usr, err := idtools.LookupUID(uid) 20 | if err != nil { 21 | return "", err 22 | } 23 | return usr.Home, nil 24 | } 25 | -------------------------------------------------------------------------------- /docker/pkg/homedir/homedir_others.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !linux 5 | // +build !linux 6 | 7 | package homedir // import "github.com/ory/dockertest/v3/docker/pkg/homedir" 8 | 9 | import ( 10 | "errors" 11 | ) 12 | 13 | // GetStatic is not needed for non-linux systems. 14 | // (Precisely, it is needed only for glibc-based linux systems.) 15 | func GetStatic() (string, error) { 16 | return "", errors.New("homedir.GetStatic() is not supported on this system") 17 | } 18 | -------------------------------------------------------------------------------- /docker/pkg/homedir/homedir_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | // +build !windows 6 | 7 | package homedir // import "github.com/ory/dockertest/v3/docker/pkg/homedir" 8 | 9 | import ( 10 | "os" 11 | 12 | "github.com/opencontainers/runc/libcontainer/user" 13 | ) 14 | 15 | // Key returns the env var name for the user's home dir based on 16 | // the platform being run on 17 | func Key() string { 18 | return "HOME" 19 | } 20 | 21 | // Get returns the home directory of the current user with the help of 22 | // environment variables depending on the target operating system. 23 | // Returned path should be used with "path/filepath" to form new paths. 24 | func Get() string { 25 | home := os.Getenv(Key()) 26 | if home == "" { 27 | if u, err := user.CurrentUser(); err == nil { 28 | return u.Home 29 | } 30 | } 31 | return home 32 | } 33 | 34 | // GetShortcutString returns the string that is shortcut to user's home directory 35 | // in the native shell of the platform running on. 36 | func GetShortcutString() string { 37 | return "~" 38 | } 39 | -------------------------------------------------------------------------------- /docker/pkg/homedir/homedir_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package homedir // import "github.com/ory/dockertest/v3/docker/pkg/homedir" 5 | 6 | import ( 7 | "os" 8 | ) 9 | 10 | // Key returns the env var name for the user's home dir based on 11 | // the platform being run on 12 | func Key() string { 13 | return "USERPROFILE" 14 | } 15 | 16 | // Get returns the home directory of the current user with the help of 17 | // environment variables depending on the target operating system. 18 | // Returned path should be used with "path/filepath" to form new paths. 19 | func Get() string { 20 | return os.Getenv(Key()) 21 | } 22 | 23 | // GetShortcutString returns the string that is shortcut to user's home directory 24 | // in the native shell of the platform running on. 25 | func GetShortcutString() string { 26 | return "%USERPROFILE%" // be careful while using in format functions 27 | } 28 | -------------------------------------------------------------------------------- /docker/pkg/idtools/idtools_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package idtools // import "github.com/ory/dockertest/v3/docker/pkg/idtools" 5 | 6 | import ( 7 | "os" 8 | 9 | "github.com/ory/dockertest/v3/docker/pkg/system" 10 | ) 11 | 12 | // Platforms such as Windows do not support the UID/GID concept. So make this 13 | // just a wrapper around system.MkdirAll. 14 | func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error { 15 | if err := system.MkdirAll(path, mode, ""); err != nil { 16 | return err 17 | } 18 | return nil 19 | } 20 | 21 | // CanAccess takes a valid (existing) directory and a uid, gid pair and determines 22 | // if that uid, gid pair has access (execute bit) to the directory 23 | // Windows does not require/support this function, so always return true 24 | func CanAccess(path string, pair IDPair) bool { 25 | return true 26 | } 27 | -------------------------------------------------------------------------------- /docker/pkg/idtools/usergroupadd_unsupported.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !linux 5 | // +build !linux 6 | 7 | package idtools // import "github.com/ory/dockertest/v3/docker/pkg/idtools" 8 | 9 | import "fmt" 10 | 11 | // AddNamespaceRangesUser takes a name and finds an unused uid, gid pair 12 | // and calls the appropriate helper function to add the group and then 13 | // the user to the group in /etc/group and /etc/passwd respectively. 14 | func AddNamespaceRangesUser(name string) (int, int, error) { 15 | return -1, -1, fmt.Errorf("No support for adding users or groups on this OS") 16 | } 17 | -------------------------------------------------------------------------------- /docker/pkg/idtools/utils_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | // +build !windows 6 | 7 | package idtools // import "github.com/ory/dockertest/v3/docker/pkg/idtools" 8 | 9 | import ( 10 | "fmt" 11 | "os/exec" 12 | "path/filepath" 13 | "strings" 14 | ) 15 | 16 | func resolveBinary(binname string) (string, error) { 17 | binaryPath, err := exec.LookPath(binname) 18 | if err != nil { 19 | return "", err 20 | } 21 | resolvedPath, err := filepath.EvalSymlinks(binaryPath) 22 | if err != nil { 23 | return "", err 24 | } 25 | //only return no error if the final resolved binary basename 26 | //matches what was searched for 27 | if filepath.Base(resolvedPath) == binname { 28 | return resolvedPath, nil 29 | } 30 | return "", fmt.Errorf("Binary %q does not resolve to a binary of that name in $PATH (%q)", binname, resolvedPath) 31 | } 32 | 33 | func execCmd(cmd, args string) ([]byte, error) { 34 | execCmd := exec.Command(cmd, strings.Split(args, " ")...) 35 | return execCmd.CombinedOutput() 36 | } 37 | -------------------------------------------------------------------------------- /docker/pkg/ioutils/buffer.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package ioutils // import "github.com/ory/dockertest/v3/docker/pkg/ioutils" 5 | 6 | import ( 7 | "errors" 8 | "io" 9 | ) 10 | 11 | var errBufferFull = errors.New("buffer is full") 12 | 13 | type fixedBuffer struct { 14 | buf []byte 15 | pos int 16 | lastRead int 17 | } 18 | 19 | func (b *fixedBuffer) Write(p []byte) (int, error) { 20 | n := copy(b.buf[b.pos:cap(b.buf)], p) 21 | b.pos += n 22 | 23 | if n < len(p) { 24 | if b.pos == cap(b.buf) { 25 | return n, errBufferFull 26 | } 27 | return n, io.ErrShortWrite 28 | } 29 | return n, nil 30 | } 31 | 32 | func (b *fixedBuffer) Read(p []byte) (int, error) { 33 | n := copy(p, b.buf[b.lastRead:b.pos]) 34 | b.lastRead += n 35 | return n, nil 36 | } 37 | 38 | func (b *fixedBuffer) Len() int { 39 | return b.pos - b.lastRead 40 | } 41 | 42 | func (b *fixedBuffer) Cap() int { 43 | return cap(b.buf) 44 | } 45 | 46 | func (b *fixedBuffer) Reset() { 47 | b.pos = 0 48 | b.lastRead = 0 49 | b.buf = b.buf[:0] 50 | } 51 | 52 | func (b *fixedBuffer) String() string { 53 | return string(b.buf[b.lastRead:b.pos]) 54 | } 55 | -------------------------------------------------------------------------------- /docker/pkg/ioutils/temp_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | // +build !windows 6 | 7 | package ioutils // import "github.com/ory/dockertest/v3/docker/pkg/ioutils" 8 | 9 | import "os" 10 | 11 | // TempDir on Unix systems is equivalent to os.MkdirTemp. 12 | func TempDir(dir, prefix string) (string, error) { 13 | return os.MkdirTemp(dir, prefix) 14 | } 15 | -------------------------------------------------------------------------------- /docker/pkg/ioutils/temp_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package ioutils // import "github.com/ory/dockertest/v3/docker/pkg/ioutils" 5 | 6 | import ( 7 | "os" 8 | 9 | "github.com/ory/dockertest/v3/docker/pkg/longpath" 10 | ) 11 | 12 | // TempDir is the equivalent of os.MkdirTemp, except that the result is in Windows longpath format. 13 | func TempDir(dir, prefix string) (string, error) { 14 | tempDir, err := os.MkdirTemp(dir, prefix) 15 | if err != nil { 16 | return "", err 17 | } 18 | return longpath.AddPrefix(tempDir), nil 19 | } 20 | -------------------------------------------------------------------------------- /docker/pkg/ioutils/writeflusher.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package ioutils // import "github.com/ory/dockertest/v3/docker/pkg/ioutils" 5 | 6 | import ( 7 | "io" 8 | "sync" 9 | ) 10 | 11 | // WriteFlusher wraps the Write and Flush operation ensuring that every write 12 | // is a flush. In addition, the Close method can be called to intercept 13 | // Read/Write calls if the targets lifecycle has already ended. 14 | type WriteFlusher struct { 15 | w io.Writer 16 | flusher flusher 17 | flushed chan struct{} 18 | flushedOnce sync.Once 19 | closed chan struct{} 20 | closeLock sync.Mutex 21 | } 22 | 23 | type flusher interface { 24 | Flush() 25 | } 26 | 27 | var errWriteFlusherClosed = io.EOF 28 | 29 | func (wf *WriteFlusher) Write(b []byte) (n int, err error) { 30 | select { 31 | case <-wf.closed: 32 | return 0, errWriteFlusherClosed 33 | default: 34 | } 35 | 36 | n, err = wf.w.Write(b) 37 | wf.Flush() // every write is a flush. 38 | return n, err 39 | } 40 | 41 | // Flush the stream immediately. 42 | func (wf *WriteFlusher) Flush() { 43 | select { 44 | case <-wf.closed: 45 | return 46 | default: 47 | } 48 | 49 | wf.flushedOnce.Do(func() { 50 | close(wf.flushed) 51 | }) 52 | wf.flusher.Flush() 53 | } 54 | 55 | // Flushed returns the state of flushed. 56 | // If it's flushed, return true, or else it return false. 57 | func (wf *WriteFlusher) Flushed() bool { 58 | // BUG(stevvooe): Remove this method. Its use is inherently racy. Seems to 59 | // be used to detect whether or a response code has been issued or not. 60 | // Another hook should be used instead. 61 | var flushed bool 62 | select { 63 | case <-wf.flushed: 64 | flushed = true 65 | default: 66 | } 67 | return flushed 68 | } 69 | 70 | // Close closes the write flusher, disallowing any further writes to the 71 | // target. After the flusher is closed, all calls to write or flush will 72 | // result in an error. 73 | func (wf *WriteFlusher) Close() error { 74 | wf.closeLock.Lock() 75 | defer wf.closeLock.Unlock() 76 | 77 | select { 78 | case <-wf.closed: 79 | return errWriteFlusherClosed 80 | default: 81 | close(wf.closed) 82 | } 83 | return nil 84 | } 85 | 86 | // NewWriteFlusher returns a new WriteFlusher. 87 | func NewWriteFlusher(w io.Writer) *WriteFlusher { 88 | var fl flusher 89 | if f, ok := w.(flusher); ok { 90 | fl = f 91 | } else { 92 | fl = &NopFlusher{} 93 | } 94 | return &WriteFlusher{w: w, flusher: fl, closed: make(chan struct{}), flushed: make(chan struct{})} 95 | } 96 | -------------------------------------------------------------------------------- /docker/pkg/ioutils/writers.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package ioutils // import "github.com/ory/dockertest/v3/docker/pkg/ioutils" 5 | 6 | import "io" 7 | 8 | // NopWriter represents a type which write operation is nop. 9 | type NopWriter struct{} 10 | 11 | func (*NopWriter) Write(buf []byte) (int, error) { 12 | return len(buf), nil 13 | } 14 | 15 | type nopWriteCloser struct { 16 | io.Writer 17 | } 18 | 19 | func (w *nopWriteCloser) Close() error { return nil } 20 | 21 | // NopWriteCloser returns a nopWriteCloser. 22 | func NopWriteCloser(w io.Writer) io.WriteCloser { 23 | return &nopWriteCloser{w} 24 | } 25 | 26 | // NopFlusher represents a type which flush operation is nop. 27 | type NopFlusher struct{} 28 | 29 | // Flush is a nop operation. 30 | func (f *NopFlusher) Flush() {} 31 | 32 | type writeCloserWrapper struct { 33 | io.Writer 34 | closer func() error 35 | } 36 | 37 | func (r *writeCloserWrapper) Close() error { 38 | return r.closer() 39 | } 40 | 41 | // NewWriteCloserWrapper returns a new io.WriteCloser. 42 | func NewWriteCloserWrapper(r io.Writer, closer func() error) io.WriteCloser { 43 | return &writeCloserWrapper{ 44 | Writer: r, 45 | closer: closer, 46 | } 47 | } 48 | 49 | // WriteCounter wraps a concrete io.Writer and hold a count of the number 50 | // of bytes written to the writer during a "session". 51 | // This can be convenient when write return is masked 52 | // (e.g., json.Encoder.Encode()) 53 | type WriteCounter struct { 54 | Count int64 55 | Writer io.Writer 56 | } 57 | 58 | // NewWriteCounter returns a new WriteCounter. 59 | func NewWriteCounter(w io.Writer) *WriteCounter { 60 | return &WriteCounter{ 61 | Writer: w, 62 | } 63 | } 64 | 65 | func (wc *WriteCounter) Write(p []byte) (count int, err error) { 66 | count, err = wc.Writer.Write(p) 67 | wc.Count += int64(count) 68 | return 69 | } 70 | -------------------------------------------------------------------------------- /docker/pkg/longpath/longpath.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // longpath introduces some constants and helper functions for handling long paths 5 | // in Windows, which are expected to be prepended with `\\?\` and followed by either 6 | // a drive letter, a UNC server\share, or a volume identifier. 7 | 8 | package longpath // import "github.com/ory/dockertest/v3/docker/pkg/longpath" 9 | 10 | import ( 11 | "strings" 12 | ) 13 | 14 | // Prefix is the longpath prefix for Windows file paths. 15 | const Prefix = `\\?\` 16 | 17 | // AddPrefix will add the Windows long path prefix to the path provided if 18 | // it does not already have it. 19 | func AddPrefix(path string) string { 20 | if !strings.HasPrefix(path, Prefix) { 21 | if strings.HasPrefix(path, `\\`) { 22 | // This is a UNC path, so we need to add 'UNC' to the path as well. 23 | path = Prefix + `UNC` + path[1:] 24 | } else { 25 | path = Prefix + path 26 | } 27 | } 28 | return path 29 | } 30 | -------------------------------------------------------------------------------- /docker/pkg/mount/flags_freebsd.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build freebsd && cgo 5 | // +build freebsd,cgo 6 | 7 | package mount // import "github.com/ory/dockertest/v3/docker/pkg/mount" 8 | 9 | /* 10 | #include 11 | */ 12 | import "C" 13 | 14 | const ( 15 | // RDONLY will mount the filesystem as read-only. 16 | RDONLY = C.MNT_RDONLY 17 | 18 | // NOSUID will not allow set-user-identifier or set-group-identifier bits to 19 | // take effect. 20 | NOSUID = C.MNT_NOSUID 21 | 22 | // NOEXEC will not allow execution of any binaries on the mounted file system. 23 | NOEXEC = C.MNT_NOEXEC 24 | 25 | // SYNCHRONOUS will allow any I/O to the file system to be done synchronously. 26 | SYNCHRONOUS = C.MNT_SYNCHRONOUS 27 | 28 | // NOATIME will not update the file access time when reading from a file. 29 | NOATIME = C.MNT_NOATIME 30 | ) 31 | 32 | // These flags are unsupported. 33 | const ( 34 | BIND = 0 35 | DIRSYNC = 0 36 | MANDLOCK = 0 37 | NODEV = 0 38 | NODIRATIME = 0 39 | UNBINDABLE = 0 40 | RUNBINDABLE = 0 41 | PRIVATE = 0 42 | RPRIVATE = 0 43 | SHARED = 0 44 | RSHARED = 0 45 | SLAVE = 0 46 | RSLAVE = 0 47 | RBIND = 0 48 | RELATIVE = 0 49 | RELATIME = 0 50 | REMOUNT = 0 51 | STRICTATIME = 0 52 | mntDetach = 0 53 | ) 54 | -------------------------------------------------------------------------------- /docker/pkg/mount/flags_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package mount // import "github.com/ory/dockertest/v3/docker/pkg/mount" 5 | 6 | import ( 7 | "golang.org/x/sys/unix" 8 | ) 9 | 10 | const ( 11 | // RDONLY will mount the file system read-only. 12 | RDONLY = unix.MS_RDONLY 13 | 14 | // NOSUID will not allow set-user-identifier or set-group-identifier bits to 15 | // take effect. 16 | NOSUID = unix.MS_NOSUID 17 | 18 | // NODEV will not interpret character or block special devices on the file 19 | // system. 20 | NODEV = unix.MS_NODEV 21 | 22 | // NOEXEC will not allow execution of any binaries on the mounted file system. 23 | NOEXEC = unix.MS_NOEXEC 24 | 25 | // SYNCHRONOUS will allow I/O to the file system to be done synchronously. 26 | SYNCHRONOUS = unix.MS_SYNCHRONOUS 27 | 28 | // DIRSYNC will force all directory updates within the file system to be done 29 | // synchronously. This affects the following system calls: create, link, 30 | // unlink, symlink, mkdir, rmdir, mknod and rename. 31 | DIRSYNC = unix.MS_DIRSYNC 32 | 33 | // REMOUNT will attempt to remount an already-mounted file system. This is 34 | // commonly used to change the mount flags for a file system, especially to 35 | // make a readonly file system writeable. It does not change device or mount 36 | // point. 37 | REMOUNT = unix.MS_REMOUNT 38 | 39 | // MANDLOCK will force mandatory locks on a filesystem. 40 | MANDLOCK = unix.MS_MANDLOCK 41 | 42 | // NOATIME will not update the file access time when reading from a file. 43 | NOATIME = unix.MS_NOATIME 44 | 45 | // NODIRATIME will not update the directory access time. 46 | NODIRATIME = unix.MS_NODIRATIME 47 | 48 | // BIND remounts a subtree somewhere else. 49 | BIND = unix.MS_BIND 50 | 51 | // RBIND remounts a subtree and all possible submounts somewhere else. 52 | RBIND = unix.MS_BIND | unix.MS_REC 53 | 54 | // UNBINDABLE creates a mount which cannot be cloned through a bind operation. 55 | UNBINDABLE = unix.MS_UNBINDABLE 56 | 57 | // RUNBINDABLE marks the entire mount tree as UNBINDABLE. 58 | RUNBINDABLE = unix.MS_UNBINDABLE | unix.MS_REC 59 | 60 | // PRIVATE creates a mount which carries no propagation abilities. 61 | PRIVATE = unix.MS_PRIVATE 62 | 63 | // RPRIVATE marks the entire mount tree as PRIVATE. 64 | RPRIVATE = unix.MS_PRIVATE | unix.MS_REC 65 | 66 | // SLAVE creates a mount which receives propagation from its master, but not 67 | // vice versa. 68 | SLAVE = unix.MS_SLAVE 69 | 70 | // RSLAVE marks the entire mount tree as SLAVE. 71 | RSLAVE = unix.MS_SLAVE | unix.MS_REC 72 | 73 | // SHARED creates a mount which provides the ability to create mirrors of 74 | // that mount such that mounts and unmounts within any of the mirrors 75 | // propagate to the other mirrors. 76 | SHARED = unix.MS_SHARED 77 | 78 | // RSHARED marks the entire mount tree as SHARED. 79 | RSHARED = unix.MS_SHARED | unix.MS_REC 80 | 81 | // RELATIME updates inode access times relative to modify or change time. 82 | RELATIME = unix.MS_RELATIME 83 | 84 | // STRICTATIME allows to explicitly request full atime updates. This makes 85 | // it possible for the kernel to default to relatime or noatime but still 86 | // allow userspace to override it. 87 | STRICTATIME = unix.MS_STRICTATIME 88 | 89 | mntDetach = unix.MNT_DETACH 90 | ) 91 | -------------------------------------------------------------------------------- /docker/pkg/mount/flags_unsupported.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build (!linux && !freebsd) || (freebsd && !cgo) 5 | // +build !linux,!freebsd freebsd,!cgo 6 | 7 | package mount // import "github.com/ory/dockertest/v3/docker/pkg/mount" 8 | 9 | // These flags are unsupported. 10 | const ( 11 | BIND = 0 12 | DIRSYNC = 0 13 | MANDLOCK = 0 14 | NOATIME = 0 15 | NODEV = 0 16 | NODIRATIME = 0 17 | NOEXEC = 0 18 | NOSUID = 0 19 | UNBINDABLE = 0 20 | RUNBINDABLE = 0 21 | PRIVATE = 0 22 | RPRIVATE = 0 23 | SHARED = 0 24 | RSHARED = 0 25 | SLAVE = 0 26 | RSLAVE = 0 27 | RBIND = 0 28 | RELATIME = 0 29 | RELATIVE = 0 30 | REMOUNT = 0 31 | STRICTATIME = 0 32 | SYNCHRONOUS = 0 33 | RDONLY = 0 34 | mntDetach = 0 35 | ) 36 | -------------------------------------------------------------------------------- /docker/pkg/mount/mounter_freebsd.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package mount // import "github.com/ory/dockertest/v3/docker/pkg/mount" 5 | 6 | /* 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | */ 14 | import "C" 15 | 16 | import ( 17 | "fmt" 18 | "strings" 19 | "unsafe" 20 | 21 | "golang.org/x/sys/unix" 22 | ) 23 | 24 | func allocateIOVecs(options []string) []C.struct_iovec { 25 | out := make([]C.struct_iovec, len(options)) 26 | for i, option := range options { 27 | out[i].iov_base = unsafe.Pointer(C.CString(option)) 28 | out[i].iov_len = C.size_t(len(option) + 1) 29 | } 30 | return out 31 | } 32 | 33 | func mount(device, target, mType string, flag uintptr, data string) error { 34 | isNullFS := false 35 | 36 | xs := strings.Split(data, ",") 37 | for _, x := range xs { 38 | if x == "bind" { 39 | isNullFS = true 40 | } 41 | } 42 | 43 | options := []string{"fspath", target} 44 | if isNullFS { 45 | options = append(options, "fstype", "nullfs", "target", device) 46 | } else { 47 | options = append(options, "fstype", mType, "from", device) 48 | } 49 | rawOptions := allocateIOVecs(options) 50 | for _, rawOption := range rawOptions { 51 | defer C.free(rawOption.iov_base) 52 | } 53 | 54 | if errno := C.nmount(&rawOptions[0], C.uint(len(options)), C.int(flag)); errno != 0 { 55 | reason := C.GoString(C.strerror(*C.__error())) 56 | return fmt.Errorf("Failed to call nmount: %s", reason) 57 | } 58 | return nil 59 | } 60 | 61 | func unmount(target string, flag int) error { 62 | return unix.Unmount(target, flag) 63 | } 64 | -------------------------------------------------------------------------------- /docker/pkg/mount/mounter_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package mount // import "github.com/ory/dockertest/v3/docker/pkg/mount" 5 | 6 | import ( 7 | "golang.org/x/sys/unix" 8 | ) 9 | 10 | const ( 11 | // ptypes is the set propagation types. 12 | ptypes = unix.MS_SHARED | unix.MS_PRIVATE | unix.MS_SLAVE | unix.MS_UNBINDABLE 13 | 14 | // pflags is the full set valid flags for a change propagation call. 15 | pflags = ptypes | unix.MS_REC | unix.MS_SILENT 16 | 17 | // broflags is the combination of bind and read only 18 | broflags = unix.MS_BIND | unix.MS_RDONLY 19 | ) 20 | 21 | // isremount returns true if either device name or flags identify a remount request, false otherwise. 22 | func isremount(device string, flags uintptr) bool { 23 | switch { 24 | // We treat device "" and "none" as a remount request to provide compatibility with 25 | // requests that don't explicitly set MS_REMOUNT such as those manipulating bind mounts. 26 | case flags&unix.MS_REMOUNT != 0, device == "", device == "none": 27 | return true 28 | default: 29 | return false 30 | } 31 | } 32 | 33 | func mount(device, target, mType string, flags uintptr, data string) error { 34 | oflags := flags &^ ptypes 35 | if !isremount(device, flags) || data != "" { 36 | // Initial call applying all non-propagation flags for mount 37 | // or remount with changed data 38 | if err := unix.Mount(device, target, mType, oflags, data); err != nil { 39 | return err 40 | } 41 | } 42 | 43 | if flags&ptypes != 0 { 44 | // Change the propagation type. 45 | if err := unix.Mount("", target, "", flags&pflags, ""); err != nil { 46 | return err 47 | } 48 | } 49 | 50 | if oflags&broflags == broflags { 51 | // Remount the bind to apply read only. 52 | return unix.Mount("", target, "", oflags|unix.MS_REMOUNT, "") 53 | } 54 | 55 | return nil 56 | } 57 | 58 | func unmount(target string, flag int) error { 59 | return unix.Unmount(target, flag) 60 | } 61 | -------------------------------------------------------------------------------- /docker/pkg/mount/mounter_unsupported.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build (!linux && !freebsd) || (freebsd && !cgo) 5 | // +build !linux,!freebsd freebsd,!cgo 6 | 7 | package mount // import "github.com/ory/dockertest/v3/docker/pkg/mount" 8 | 9 | func mount(device, target, mType string, flag uintptr, data string) error { 10 | panic("Not implemented") 11 | } 12 | 13 | func unmount(target string, flag int) error { 14 | panic("Not implemented") 15 | } 16 | -------------------------------------------------------------------------------- /docker/pkg/mount/mountinfo.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package mount // import "github.com/ory/dockertest/v3/docker/pkg/mount" 5 | 6 | // Info reveals information about a particular mounted filesystem. This 7 | // struct is populated from the content in the /proc//mountinfo file. 8 | type Info struct { 9 | // ID is a unique identifier of the mount (may be reused after umount). 10 | ID int 11 | 12 | // Parent indicates the ID of the mount parent (or of self for the top of the 13 | // mount tree). 14 | Parent int 15 | 16 | // Major indicates one half of the device ID which identifies the device class. 17 | Major int 18 | 19 | // Minor indicates one half of the device ID which identifies a specific 20 | // instance of device. 21 | Minor int 22 | 23 | // Root of the mount within the filesystem. 24 | Root string 25 | 26 | // Mountpoint indicates the mount point relative to the process's root. 27 | Mountpoint string 28 | 29 | // Opts represents mount-specific options. 30 | Opts string 31 | 32 | // Optional represents optional fields. 33 | Optional string 34 | 35 | // Fstype indicates the type of filesystem, such as EXT3. 36 | Fstype string 37 | 38 | // Source indicates filesystem specific information or "none". 39 | Source string 40 | 41 | // VfsOpts represents per super block options. 42 | VfsOpts string 43 | } 44 | -------------------------------------------------------------------------------- /docker/pkg/mount/mountinfo_freebsd.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package mount // import "github.com/ory/dockertest/v3/docker/pkg/mount" 5 | 6 | /* 7 | #include 8 | #include 9 | #include 10 | */ 11 | import "C" 12 | 13 | import ( 14 | "fmt" 15 | "reflect" 16 | "unsafe" 17 | ) 18 | 19 | // Parse /proc/self/mountinfo because comparing Dev and ino does not work from 20 | // bind mounts. 21 | func parseMountTable() ([]*Info, error) { 22 | var rawEntries *C.struct_statfs 23 | 24 | count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT)) 25 | if count == 0 { 26 | return nil, fmt.Errorf("Failed to call getmntinfo") 27 | } 28 | 29 | var entries []C.struct_statfs 30 | header := (*reflect.SliceHeader)(unsafe.Pointer(&entries)) 31 | header.Cap = count 32 | header.Len = count 33 | header.Data = uintptr(unsafe.Pointer(rawEntries)) 34 | 35 | var out []*Info 36 | for _, entry := range entries { 37 | var mountinfo Info 38 | mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0]) 39 | mountinfo.Source = C.GoString(&entry.f_mntfromname[0]) 40 | mountinfo.Fstype = C.GoString(&entry.f_fstypename[0]) 41 | out = append(out, &mountinfo) 42 | } 43 | return out, nil 44 | } 45 | -------------------------------------------------------------------------------- /docker/pkg/mount/mountinfo_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package mount // import "github.com/ory/dockertest/v3/docker/pkg/mount" 5 | 6 | import ( 7 | "bufio" 8 | "fmt" 9 | "io" 10 | "os" 11 | "strings" 12 | ) 13 | 14 | const ( 15 | /* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue 16 | (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) 17 | 18 | (1) mount ID: unique identifier of the mount (may be reused after umount) 19 | (2) parent ID: ID of parent (or of self for the top of the mount tree) 20 | (3) major:minor: value of st_dev for files on filesystem 21 | (4) root: root of the mount within the filesystem 22 | (5) mount point: mount point relative to the process's root 23 | (6) mount options: per mount options 24 | (7) optional fields: zero or more fields of the form "tag[:value]" 25 | (8) separator: marks the end of the optional fields 26 | (9) filesystem type: name of filesystem of the form "type[.subtype]" 27 | (10) mount source: filesystem specific information or "none" 28 | (11) super options: per super block options*/ 29 | mountinfoFormat = "%d %d %d:%d %s %s %s %s" 30 | ) 31 | 32 | // Parse /proc/self/mountinfo because comparing Dev and ino does not work from 33 | // bind mounts 34 | func parseMountTable() ([]*Info, error) { 35 | f, err := os.Open("/proc/self/mountinfo") 36 | if err != nil { 37 | return nil, err 38 | } 39 | defer f.Close() 40 | 41 | return parseInfoFile(f) 42 | } 43 | 44 | func parseInfoFile(r io.Reader) ([]*Info, error) { 45 | var ( 46 | s = bufio.NewScanner(r) 47 | out = []*Info{} 48 | ) 49 | 50 | for s.Scan() { 51 | if err := s.Err(); err != nil { 52 | return nil, err 53 | } 54 | 55 | var ( 56 | p = &Info{} 57 | text = s.Text() 58 | optionalFields string 59 | ) 60 | 61 | if _, err := fmt.Sscanf(text, mountinfoFormat, 62 | &p.ID, &p.Parent, &p.Major, &p.Minor, 63 | &p.Root, &p.Mountpoint, &p.Opts, &optionalFields); err != nil { 64 | return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err) 65 | } 66 | // Safe as mountinfo encodes mountpoints with spaces as \040. 67 | index := strings.Index(text, " - ") 68 | postSeparatorFields := strings.Fields(text[index+3:]) 69 | if len(postSeparatorFields) < 3 { 70 | return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text) 71 | } 72 | 73 | if optionalFields != "-" { 74 | p.Optional = optionalFields 75 | } 76 | 77 | p.Fstype = postSeparatorFields[0] 78 | p.Source = postSeparatorFields[1] 79 | p.VfsOpts = strings.Join(postSeparatorFields[2:], " ") 80 | out = append(out, p) 81 | } 82 | return out, nil 83 | } 84 | 85 | // PidMountInfo collects the mounts for a specific process ID. If the process 86 | // ID is unknown, it is better to use `GetMounts` which will inspect 87 | // "/proc/self/mountinfo" instead. 88 | func PidMountInfo(pid int) ([]*Info, error) { 89 | f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid)) 90 | if err != nil { 91 | return nil, err 92 | } 93 | defer f.Close() 94 | 95 | return parseInfoFile(f) 96 | } 97 | -------------------------------------------------------------------------------- /docker/pkg/mount/mountinfo_unsupported.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build (!windows && !linux && !freebsd) || (freebsd && !cgo) 5 | // +build !windows,!linux,!freebsd freebsd,!cgo 6 | 7 | package mount // import "github.com/ory/dockertest/v3/docker/pkg/mount" 8 | 9 | import ( 10 | "fmt" 11 | "runtime" 12 | ) 13 | 14 | func parseMountTable() ([]*Info, error) { 15 | return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) 16 | } 17 | -------------------------------------------------------------------------------- /docker/pkg/mount/mountinfo_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package mount // import "github.com/ory/dockertest/v3/docker/pkg/mount" 5 | 6 | func parseMountTable() ([]*Info, error) { 7 | // Do NOT return an error! 8 | return nil, nil 9 | } 10 | -------------------------------------------------------------------------------- /docker/pkg/mount/sharedsubtree_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package mount // import "github.com/ory/dockertest/v3/docker/pkg/mount" 5 | 6 | // MakeShared ensures a mounted filesystem has the SHARED mount option enabled. 7 | // See the supported options in flags.go for further reference. 8 | func MakeShared(mountPoint string) error { 9 | return ensureMountedAs(mountPoint, "shared") 10 | } 11 | 12 | // MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled. 13 | // See the supported options in flags.go for further reference. 14 | func MakeRShared(mountPoint string) error { 15 | return ensureMountedAs(mountPoint, "rshared") 16 | } 17 | 18 | // MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled. 19 | // See the supported options in flags.go for further reference. 20 | func MakePrivate(mountPoint string) error { 21 | return ensureMountedAs(mountPoint, "private") 22 | } 23 | 24 | // MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option 25 | // enabled. See the supported options in flags.go for further reference. 26 | func MakeRPrivate(mountPoint string) error { 27 | return ensureMountedAs(mountPoint, "rprivate") 28 | } 29 | 30 | // MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled. 31 | // See the supported options in flags.go for further reference. 32 | func MakeSlave(mountPoint string) error { 33 | return ensureMountedAs(mountPoint, "slave") 34 | } 35 | 36 | // MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled. 37 | // See the supported options in flags.go for further reference. 38 | func MakeRSlave(mountPoint string) error { 39 | return ensureMountedAs(mountPoint, "rslave") 40 | } 41 | 42 | // MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option 43 | // enabled. See the supported options in flags.go for further reference. 44 | func MakeUnbindable(mountPoint string) error { 45 | return ensureMountedAs(mountPoint, "unbindable") 46 | } 47 | 48 | // MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount 49 | // option enabled. See the supported options in flags.go for further reference. 50 | func MakeRUnbindable(mountPoint string) error { 51 | return ensureMountedAs(mountPoint, "runbindable") 52 | } 53 | 54 | func ensureMountedAs(mountPoint, options string) error { 55 | mounted, err := Mounted(mountPoint) 56 | if err != nil { 57 | return err 58 | } 59 | 60 | if !mounted { 61 | if err := Mount(mountPoint, mountPoint, "none", "bind,rw"); err != nil { 62 | return err 63 | } 64 | } 65 | if _, err = Mounted(mountPoint); err != nil { 66 | return err 67 | } 68 | 69 | return ForceMount("", mountPoint, "none", options) 70 | } 71 | -------------------------------------------------------------------------------- /docker/pkg/system/chtimes.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import ( 7 | "os" 8 | "time" 9 | ) 10 | 11 | // Chtimes changes the access time and modified time of a file at the given path 12 | func Chtimes(name string, atime time.Time, mtime time.Time) error { 13 | unixMinTime := time.Unix(0, 0) 14 | unixMaxTime := maxTime 15 | 16 | // If the modified time is prior to the Unix Epoch, or after the 17 | // end of Unix Time, os.Chtimes has undefined behavior 18 | // default to Unix Epoch in this case, just in case 19 | 20 | if atime.Before(unixMinTime) || atime.After(unixMaxTime) { 21 | atime = unixMinTime 22 | } 23 | 24 | if mtime.Before(unixMinTime) || mtime.After(unixMaxTime) { 25 | mtime = unixMinTime 26 | } 27 | 28 | if err := os.Chtimes(name, atime, mtime); err != nil { 29 | return err 30 | } 31 | 32 | // Take platform specific action for setting create time. 33 | return setCTime(name, mtime) 34 | } 35 | -------------------------------------------------------------------------------- /docker/pkg/system/chtimes_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | // +build !windows 6 | 7 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 8 | 9 | import ( 10 | "time" 11 | ) 12 | 13 | // setCTime will set the create time on a file. On Unix, the create 14 | // time is updated as a side effect of setting the modified time, so 15 | // no action is required. 16 | func setCTime(path string, ctime time.Time) error { 17 | return nil 18 | } 19 | -------------------------------------------------------------------------------- /docker/pkg/system/chtimes_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import ( 7 | "time" 8 | 9 | "golang.org/x/sys/windows" 10 | ) 11 | 12 | // setCTime will set the create time on a file. On Windows, this requires 13 | // calling SetFileTime and explicitly including the create time. 14 | func setCTime(path string, ctime time.Time) error { 15 | ctimespec := windows.NsecToTimespec(ctime.UnixNano()) 16 | pathp, e := windows.UTF16PtrFromString(path) 17 | if e != nil { 18 | return e 19 | } 20 | h, e := windows.CreateFile(pathp, 21 | windows.FILE_WRITE_ATTRIBUTES, windows.FILE_SHARE_WRITE, nil, 22 | windows.OPEN_EXISTING, windows.FILE_FLAG_BACKUP_SEMANTICS, 0) 23 | if e != nil { 24 | return e 25 | } 26 | defer windows.Close(h) 27 | c := windows.NsecToFiletime(windows.TimespecToNsec(ctimespec)) 28 | return windows.SetFileTime(h, &c, nil, nil) 29 | } 30 | -------------------------------------------------------------------------------- /docker/pkg/system/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import ( 7 | "errors" 8 | ) 9 | 10 | var ( 11 | // ErrNotSupportedPlatform means the platform is not supported. 12 | ErrNotSupportedPlatform = errors.New("platform and architecture is not supported") 13 | 14 | // ErrNotSupportedOperatingSystem means the operating system is not supported. 15 | ErrNotSupportedOperatingSystem = errors.New("operating system is not supported") 16 | ) 17 | -------------------------------------------------------------------------------- /docker/pkg/system/exitcode.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import ( 7 | "fmt" 8 | "os/exec" 9 | "syscall" 10 | ) 11 | 12 | // GetExitCode returns the ExitStatus of the specified error if its type is 13 | // exec.ExitError, returns 0 and an error otherwise. 14 | func GetExitCode(err error) (int, error) { 15 | exitCode := 0 16 | if exiterr, ok := err.(*exec.ExitError); ok { 17 | if procExit, ok := exiterr.Sys().(syscall.WaitStatus); ok { 18 | return procExit.ExitStatus(), nil 19 | } 20 | } 21 | return exitCode, fmt.Errorf("failed to get exit code") 22 | } 23 | -------------------------------------------------------------------------------- /docker/pkg/system/filesys.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | // +build !windows 6 | 7 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 8 | 9 | import ( 10 | "os" 11 | "path/filepath" 12 | ) 13 | 14 | // MkdirAllWithACL is a wrapper for MkdirAll on unix systems. 15 | func MkdirAllWithACL(path string, perm os.FileMode, sddl string) error { 16 | return MkdirAll(path, perm, sddl) 17 | } 18 | 19 | // MkdirAll creates a directory named path along with any necessary parents, 20 | // with permission specified by attribute perm for all dir created. 21 | func MkdirAll(path string, perm os.FileMode, sddl string) error { 22 | return os.MkdirAll(path, perm) 23 | } 24 | 25 | // IsAbs is a platform-specific wrapper for filepath.IsAbs. 26 | func IsAbs(path string) bool { 27 | return filepath.IsAbs(path) 28 | } 29 | 30 | // The functions below here are wrappers for the equivalents in the os and ioutils packages. 31 | // They are passthrough on Unix platforms, and only relevant on Windows. 32 | 33 | // CreateSequential creates the named file with mode 0666 (before umask), truncating 34 | // it if it already exists. If successful, methods on the returned 35 | // File can be used for I/O; the associated file descriptor has mode 36 | // O_RDWR. 37 | // If there is an error, it will be of type *PathError. 38 | func CreateSequential(name string) (*os.File, error) { 39 | return os.Create(name) 40 | } 41 | 42 | // OpenSequential opens the named file for reading. If successful, methods on 43 | // the returned file can be used for reading; the associated file 44 | // descriptor has mode O_RDONLY. 45 | // If there is an error, it will be of type *PathError. 46 | func OpenSequential(name string) (*os.File, error) { 47 | return os.Open(name) 48 | } 49 | 50 | // OpenFileSequential is the generalized open call; most users will use Open 51 | // or Create instead. It opens the named file with specified flag 52 | // (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful, 53 | // methods on the returned File can be used for I/O. 54 | // If there is an error, it will be of type *PathError. 55 | func OpenFileSequential(name string, flag int, perm os.FileMode) (*os.File, error) { 56 | return os.OpenFile(name, flag, perm) 57 | } 58 | 59 | // TempFileSequential creates a new temporary file in the directory dir 60 | // with a name beginning with prefix, opens the file for reading 61 | // and writing, and returns the resulting *os.File. 62 | // If dir is the empty string, TempFile uses the default directory 63 | // for temporary files (see os.TempDir). 64 | // Multiple programs calling TempFile simultaneously 65 | // will not choose the same file. The caller can use f.Name() 66 | // to find the pathname of the file. It is the caller's responsibility 67 | // to remove the file when no longer needed. 68 | func TempFileSequential(dir, prefix string) (f *os.File, err error) { 69 | return os.CreateTemp(dir, prefix) 70 | } 71 | -------------------------------------------------------------------------------- /docker/pkg/system/init.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import ( 7 | "syscall" 8 | "time" 9 | "unsafe" 10 | ) 11 | 12 | // Used by chtimes 13 | var maxTime time.Time 14 | 15 | func init() { 16 | // chtimes initialization 17 | if unsafe.Sizeof(syscall.Timespec{}.Nsec) == 8 { 18 | // This is a 64 bit timespec 19 | // os.Chtimes limits time to the following 20 | maxTime = time.Unix(0, 1<<63-1) 21 | } else { 22 | // This is a 32 bit timespec 23 | maxTime = time.Unix(1<<31-1, 0) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /docker/pkg/system/init_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | // +build !windows 6 | 7 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 8 | 9 | // InitLCOW does nothing since LCOW is a windows only feature 10 | func InitLCOW(experimental bool) { 11 | } 12 | -------------------------------------------------------------------------------- /docker/pkg/system/init_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | // lcowSupported determines if Linux Containers on Windows are supported. 7 | var lcowSupported = false 8 | 9 | // InitLCOW sets whether LCOW is supported or not 10 | func InitLCOW(experimental bool) { 11 | v := GetOSVersion() 12 | if experimental && v.Build >= 16299 { 13 | lcowSupported = true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /docker/pkg/system/lcow.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import ( 7 | "fmt" 8 | "runtime" 9 | "strings" 10 | 11 | specs "github.com/opencontainers/image-spec/specs-go/v1" 12 | ) 13 | 14 | // ValidatePlatform determines if a platform structure is valid. 15 | // TODO This is a temporary function - can be replaced by parsing from 16 | // https://github.com/containerd/containerd/pull/1403/files at a later date. 17 | // @jhowardmsft 18 | func ValidatePlatform(platform *specs.Platform) error { 19 | platform.Architecture = strings.ToLower(platform.Architecture) 20 | platform.OS = strings.ToLower(platform.OS) 21 | // Based on https://github.com/moby/moby/pull/34642#issuecomment-330375350, do 22 | // not support anything except operating system. 23 | if platform.Architecture != "" { 24 | return fmt.Errorf("invalid platform architecture %q", platform.Architecture) 25 | } 26 | if platform.OS != "" { 27 | if !(platform.OS == runtime.GOOS || (LCOWSupported() && platform.OS == "linux")) { 28 | return fmt.Errorf("invalid platform os %q", platform.OS) 29 | } 30 | } 31 | if len(platform.OSFeatures) != 0 { 32 | return fmt.Errorf("invalid platform osfeatures %q", platform.OSFeatures) 33 | } 34 | if platform.OSVersion != "" { 35 | return fmt.Errorf("invalid platform osversion %q", platform.OSVersion) 36 | } 37 | if platform.Variant != "" { 38 | return fmt.Errorf("invalid platform variant %q", platform.Variant) 39 | } 40 | return nil 41 | } 42 | 43 | // ParsePlatform parses a platform string in the format os[/arch[/variant] 44 | // into an OCI image-spec platform structure. 45 | // TODO This is a temporary function - can be replaced by parsing from 46 | // https://github.com/containerd/containerd/pull/1403/files at a later date. 47 | // @jhowardmsft 48 | func ParsePlatform(in string) *specs.Platform { 49 | p := &specs.Platform{} 50 | elements := strings.SplitN(strings.ToLower(in), "/", 3) 51 | if len(elements) == 3 { 52 | p.Variant = elements[2] 53 | } 54 | if len(elements) >= 2 { 55 | p.Architecture = elements[1] 56 | } 57 | if len(elements) >= 1 { 58 | p.OS = elements[0] 59 | } 60 | return p 61 | } 62 | 63 | // IsOSSupported determines if an operating system is supported by the host 64 | func IsOSSupported(os string) bool { 65 | if runtime.GOOS == os { 66 | return true 67 | } 68 | if LCOWSupported() && os == "linux" { 69 | return true 70 | } 71 | return false 72 | } 73 | -------------------------------------------------------------------------------- /docker/pkg/system/lcow_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | // +build !windows 6 | 7 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 8 | 9 | // LCOWSupported returns true if Linux containers on Windows are supported. 10 | func LCOWSupported() bool { 11 | return false 12 | } 13 | -------------------------------------------------------------------------------- /docker/pkg/system/lcow_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | // LCOWSupported returns true if Linux containers on Windows are supported. 7 | func LCOWSupported() bool { 8 | return lcowSupported 9 | } 10 | -------------------------------------------------------------------------------- /docker/pkg/system/lstat_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | // +build !windows 6 | 7 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 8 | 9 | import ( 10 | "syscall" 11 | ) 12 | 13 | // Lstat takes a path to a file and returns 14 | // a system.StatT type pertaining to that file. 15 | // 16 | // Throws an error if the file does not exist 17 | func Lstat(path string) (*StatT, error) { 18 | s := &syscall.Stat_t{} 19 | if err := syscall.Lstat(path, s); err != nil { 20 | return nil, err 21 | } 22 | return fromStatT(s) 23 | } 24 | -------------------------------------------------------------------------------- /docker/pkg/system/lstat_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import "os" 7 | 8 | // Lstat calls os.Lstat to get a fileinfo interface back. 9 | // This is then copied into our own locally defined structure. 10 | func Lstat(path string) (*StatT, error) { 11 | fi, err := os.Lstat(path) 12 | if err != nil { 13 | return nil, err 14 | } 15 | 16 | return fromStatT(&fi) 17 | } 18 | -------------------------------------------------------------------------------- /docker/pkg/system/meminfo.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | // MemInfo contains memory statistics of the host system. 7 | type MemInfo struct { 8 | // Total usable RAM (i.e. physical RAM minus a few reserved bits and the 9 | // kernel binary code). 10 | MemTotal int64 11 | 12 | // Amount of free memory. 13 | MemFree int64 14 | 15 | // Total amount of swap space available. 16 | SwapTotal int64 17 | 18 | // Amount of swap space that is currently unused. 19 | SwapFree int64 20 | } 21 | -------------------------------------------------------------------------------- /docker/pkg/system/meminfo_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import ( 7 | "bufio" 8 | "io" 9 | "os" 10 | "strconv" 11 | "strings" 12 | 13 | "github.com/docker/go-units" 14 | ) 15 | 16 | // ReadMemInfo retrieves memory statistics of the host system and returns a 17 | // MemInfo type. 18 | func ReadMemInfo() (*MemInfo, error) { 19 | file, err := os.Open("/proc/meminfo") 20 | if err != nil { 21 | return nil, err 22 | } 23 | defer file.Close() 24 | return parseMemInfo(file) 25 | } 26 | 27 | // parseMemInfo parses the /proc/meminfo file into 28 | // a MemInfo object given an io.Reader to the file. 29 | // Throws error if there are problems reading from the file 30 | func parseMemInfo(reader io.Reader) (*MemInfo, error) { 31 | meminfo := &MemInfo{} 32 | scanner := bufio.NewScanner(reader) 33 | for scanner.Scan() { 34 | // Expected format: ["MemTotal:", "1234", "kB"] 35 | parts := strings.Fields(scanner.Text()) 36 | 37 | // Sanity checks: Skip malformed entries. 38 | if len(parts) < 3 || parts[2] != "kB" { 39 | continue 40 | } 41 | 42 | // Convert to bytes. 43 | size, err := strconv.Atoi(parts[1]) 44 | if err != nil { 45 | continue 46 | } 47 | bytes := int64(size) * units.KiB 48 | 49 | switch parts[0] { 50 | case "MemTotal:": 51 | meminfo.MemTotal = bytes 52 | case "MemFree:": 53 | meminfo.MemFree = bytes 54 | case "SwapTotal:": 55 | meminfo.SwapTotal = bytes 56 | case "SwapFree:": 57 | meminfo.SwapFree = bytes 58 | } 59 | 60 | } 61 | 62 | // Handle errors that may have occurred during the reading of the file. 63 | if err := scanner.Err(); err != nil { 64 | return nil, err 65 | } 66 | 67 | return meminfo, nil 68 | } 69 | -------------------------------------------------------------------------------- /docker/pkg/system/meminfo_unsupported.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !linux && !windows 5 | // +build !linux,!windows 6 | 7 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 8 | 9 | // ReadMemInfo is not supported on platforms other than linux and windows. 10 | func ReadMemInfo() (*MemInfo, error) { 11 | return nil, ErrNotSupportedPlatform 12 | } 13 | -------------------------------------------------------------------------------- /docker/pkg/system/meminfo_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import ( 7 | "unsafe" 8 | 9 | "golang.org/x/sys/windows" 10 | ) 11 | 12 | var ( 13 | modkernel32 = windows.NewLazySystemDLL("kernel32.dll") 14 | 15 | procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx") 16 | ) 17 | 18 | // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366589(v=vs.85).aspx 19 | // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366770(v=vs.85).aspx 20 | type memorystatusex struct { 21 | dwLength uint32 22 | dwMemoryLoad uint32 23 | ullTotalPhys uint64 24 | ullAvailPhys uint64 25 | ullTotalPageFile uint64 26 | ullAvailPageFile uint64 27 | ullTotalVirtual uint64 28 | ullAvailVirtual uint64 29 | ullAvailExtendedVirtual uint64 30 | } 31 | 32 | // ReadMemInfo retrieves memory statistics of the host system and returns a 33 | // 34 | // MemInfo type. 35 | func ReadMemInfo() (*MemInfo, error) { 36 | msi := &memorystatusex{ 37 | dwLength: 64, 38 | } 39 | r1, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(msi))) 40 | if r1 == 0 { 41 | return &MemInfo{}, nil 42 | } 43 | return &MemInfo{ 44 | MemTotal: int64(msi.ullTotalPhys), 45 | MemFree: int64(msi.ullAvailPhys), 46 | SwapTotal: int64(msi.ullTotalPageFile), 47 | SwapFree: int64(msi.ullAvailPageFile), 48 | }, nil 49 | } 50 | -------------------------------------------------------------------------------- /docker/pkg/system/mknod.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows && !freebsd 5 | // +build !windows,!freebsd 6 | 7 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 8 | 9 | import ( 10 | "golang.org/x/sys/unix" 11 | ) 12 | 13 | // Mknod creates a filesystem node (file, device special file or named pipe) named path 14 | // with attributes specified by mode and dev. 15 | func Mknod(path string, mode uint32, dev int) error { 16 | return unix.Mknod(path, mode, dev) 17 | } 18 | 19 | // Mkdev is used to build the value of linux devices (in /dev/) which specifies major 20 | // and minor number of the newly created device special file. 21 | // Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes. 22 | // They are, from low to high: the lower 8 bits of the minor, then 12 bits of the major, 23 | // then the top 12 bits of the minor. 24 | func Mkdev(major int64, minor int64) uint32 { 25 | return uint32(unix.Mkdev(uint32(major), uint32(minor))) 26 | } 27 | -------------------------------------------------------------------------------- /docker/pkg/system/mknod_freebsd.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build freebsd 5 | // +build freebsd 6 | 7 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 8 | 9 | import ( 10 | "golang.org/x/sys/unix" 11 | ) 12 | 13 | // Mknod creates a filesystem node (file, device special file or named pipe) named path 14 | // with attributes specified by mode and dev. 15 | func Mknod(path string, mode uint32, dev int) error { 16 | return unix.Mknod(path, mode, uint64(dev)) 17 | } 18 | 19 | // Mkdev is used to build the value of linux devices (in /dev/) which specifies major 20 | // and minor number of the newly created device special file. 21 | // Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes. 22 | // They are, from low to high: the lower 8 bits of the minor, then 12 bits of the major, 23 | // then the top 12 bits of the minor. 24 | func Mkdev(major int64, minor int64) uint32 { 25 | return uint32(unix.Mkdev(uint32(major), uint32(minor))) 26 | } 27 | -------------------------------------------------------------------------------- /docker/pkg/system/mknod_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build windows 5 | // +build windows 6 | 7 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 8 | 9 | // Mknod is not implemented on Windows. 10 | func Mknod(path string, mode uint32, dev int) error { 11 | return ErrNotSupportedPlatform 12 | } 13 | 14 | // Mkdev is not implemented on Windows. 15 | func Mkdev(major int64, minor int64) uint32 { 16 | panic("Mkdev not implemented on Windows.") 17 | } 18 | -------------------------------------------------------------------------------- /docker/pkg/system/path.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import ( 7 | "fmt" 8 | "path/filepath" 9 | "runtime" 10 | "strings" 11 | 12 | "github.com/containerd/continuity/pathdriver" 13 | ) 14 | 15 | const defaultUnixPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 16 | 17 | // DefaultPathEnv is unix style list of directories to search for 18 | // executables. Each directory is separated from the next by a colon 19 | // ':' character . 20 | func DefaultPathEnv(os string) string { 21 | if runtime.GOOS == "windows" { 22 | if os != runtime.GOOS { 23 | return defaultUnixPathEnv 24 | } 25 | // Deliberately empty on Windows containers on Windows as the default path will be set by 26 | // the container. Docker has no context of what the default path should be. 27 | return "" 28 | } 29 | return defaultUnixPathEnv 30 | 31 | } 32 | 33 | // CheckSystemDriveAndRemoveDriveLetter verifies that a path, if it includes a drive letter, 34 | // is the system drive. 35 | // On Linux: this is a no-op. 36 | // On Windows: this does the following> 37 | // CheckSystemDriveAndRemoveDriveLetter verifies and manipulates a Windows path. 38 | // This is used, for example, when validating a user provided path in docker cp. 39 | // If a drive letter is supplied, it must be the system drive. The drive letter 40 | // is always removed. Also, it translates it to OS semantics (IOW / to \). We 41 | // need the path in this syntax so that it can ultimately be concatenated with 42 | // a Windows long-path which doesn't support drive-letters. Examples: 43 | // C: --> Fail 44 | // C:\ --> \ 45 | // a --> a 46 | // /a --> \a 47 | // d:\ --> Fail 48 | func CheckSystemDriveAndRemoveDriveLetter(path string, driver pathdriver.PathDriver) (string, error) { 49 | if runtime.GOOS != "windows" || LCOWSupported() { 50 | return path, nil 51 | } 52 | 53 | if len(path) == 2 && string(path[1]) == ":" { 54 | return "", fmt.Errorf("No relative path specified in %q", path) 55 | } 56 | if !driver.IsAbs(path) || len(path) < 2 { 57 | return filepath.FromSlash(path), nil 58 | } 59 | if string(path[1]) == ":" && !strings.EqualFold(string(path[0]), "c") { 60 | return "", fmt.Errorf("The specified path is not on the system drive (C:)") 61 | } 62 | return filepath.FromSlash(path[2:]), nil 63 | } 64 | -------------------------------------------------------------------------------- /docker/pkg/system/process_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build linux || freebsd || darwin 5 | // +build linux freebsd darwin 6 | 7 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 8 | 9 | import ( 10 | "syscall" 11 | 12 | "golang.org/x/sys/unix" 13 | ) 14 | 15 | // IsProcessAlive returns true if process with a given pid is running. 16 | func IsProcessAlive(pid int) bool { 17 | err := unix.Kill(pid, syscall.Signal(0)) 18 | if err == nil || err == unix.EPERM { 19 | return true 20 | } 21 | 22 | return false 23 | } 24 | 25 | // KillProcess force-stops a process. 26 | func KillProcess(pid int) { 27 | unix.Kill(pid, unix.SIGKILL) 28 | } 29 | -------------------------------------------------------------------------------- /docker/pkg/system/process_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import "os" 7 | 8 | // IsProcessAlive returns true if process with a given pid is running. 9 | func IsProcessAlive(pid int) bool { 10 | _, err := os.FindProcess(pid) 11 | 12 | return err == nil 13 | } 14 | 15 | // KillProcess force-stops a process. 16 | func KillProcess(pid int) { 17 | p, err := os.FindProcess(pid) 18 | if err == nil { 19 | p.Kill() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /docker/pkg/system/rm.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import ( 7 | "fmt" 8 | "os" 9 | "syscall" 10 | "time" 11 | 12 | "github.com/ory/dockertest/v3/docker/pkg/mount" 13 | ) 14 | 15 | // EnsureRemoveAll wraps `os.RemoveAll` to check for specific errors that can 16 | // often be remedied. 17 | // Only use `EnsureRemoveAll` if you really want to make every effort to remove 18 | // a directory. 19 | // 20 | // Because of the way `os.Remove` (and by extension `os.RemoveAll`) works, there 21 | // can be a race between reading directory entries and then actually attempting 22 | // to remove everything in the directory. 23 | // These types of errors do not need to be returned since it's ok for the dir to 24 | // be gone we can just retry the remove operation. 25 | // 26 | // This should not return a `os.ErrNotExist` kind of error under any circumstances 27 | func EnsureRemoveAll(dir string) error { 28 | notExistErr := make(map[string]bool) 29 | 30 | // track retries 31 | exitOnErr := make(map[string]int) 32 | maxRetry := 50 33 | 34 | // Attempt to unmount anything beneath this dir first 35 | mount.RecursiveUnmount(dir) 36 | 37 | for { 38 | err := os.RemoveAll(dir) 39 | if err == nil { 40 | return err 41 | } 42 | 43 | pe, ok := err.(*os.PathError) 44 | if !ok { 45 | return err 46 | } 47 | 48 | if os.IsNotExist(err) { 49 | if notExistErr[pe.Path] { 50 | return err 51 | } 52 | notExistErr[pe.Path] = true 53 | 54 | // There is a race where some subdir can be removed but after the parent 55 | // dir entries have been read. 56 | // So the path could be from `os.Remove(subdir)` 57 | // If the reported non-existent path is not the passed in `dir` we 58 | // should just retry, but otherwise return with no error. 59 | if pe.Path == dir { 60 | return nil 61 | } 62 | continue 63 | } 64 | 65 | if pe.Err != syscall.EBUSY { 66 | return err 67 | } 68 | 69 | if mounted, _ := mount.Mounted(pe.Path); mounted { 70 | if e := mount.Unmount(pe.Path); e != nil { 71 | if mounted, _ := mount.Mounted(pe.Path); mounted { 72 | return fmt.Errorf("error while removing %s: %w", dir, e) 73 | } 74 | } 75 | } 76 | 77 | if exitOnErr[pe.Path] == maxRetry { 78 | return err 79 | } 80 | exitOnErr[pe.Path]++ 81 | time.Sleep(100 * time.Millisecond) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /docker/pkg/system/stat_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import "syscall" 7 | 8 | // fromStatT converts a syscall.Stat_t type to a system.Stat_t type 9 | func fromStatT(s *syscall.Stat_t) (*StatT, error) { 10 | return &StatT{size: s.Size, 11 | mode: uint32(s.Mode), 12 | uid: s.Uid, 13 | gid: s.Gid, 14 | rdev: uint64(s.Rdev), 15 | mtim: s.Mtimespec}, nil 16 | } 17 | -------------------------------------------------------------------------------- /docker/pkg/system/stat_freebsd.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import "syscall" 7 | 8 | // fromStatT converts a syscall.Stat_t type to a system.Stat_t type 9 | func fromStatT(s *syscall.Stat_t) (*StatT, error) { 10 | return &StatT{size: s.Size, 11 | mode: uint32(s.Mode), 12 | uid: s.Uid, 13 | gid: s.Gid, 14 | rdev: uint64(s.Rdev), 15 | mtim: s.Mtimespec}, nil 16 | } 17 | -------------------------------------------------------------------------------- /docker/pkg/system/stat_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import "syscall" 7 | 8 | // fromStatT converts a syscall.Stat_t type to a system.Stat_t type 9 | func fromStatT(s *syscall.Stat_t) (*StatT, error) { 10 | return &StatT{size: s.Size, 11 | mode: s.Mode, 12 | uid: s.Uid, 13 | gid: s.Gid, 14 | rdev: uint64(s.Rdev), 15 | mtim: s.Mtim}, nil 16 | } 17 | 18 | // FromStatT converts a syscall.Stat_t type to a system.Stat_t type 19 | // This is exposed on Linux as pkg/archive/changes uses it. 20 | func FromStatT(s *syscall.Stat_t) (*StatT, error) { 21 | return fromStatT(s) 22 | } 23 | -------------------------------------------------------------------------------- /docker/pkg/system/stat_openbsd.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import "syscall" 7 | 8 | // fromStatT converts a syscall.Stat_t type to a system.Stat_t type 9 | func fromStatT(s *syscall.Stat_t) (*StatT, error) { 10 | return &StatT{size: s.Size, 11 | mode: uint32(s.Mode), 12 | uid: s.Uid, 13 | gid: s.Gid, 14 | rdev: uint64(s.Rdev), 15 | mtim: s.Mtim}, nil 16 | } 17 | -------------------------------------------------------------------------------- /docker/pkg/system/stat_solaris.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import "syscall" 7 | 8 | // fromStatT converts a syscall.Stat_t type to a system.Stat_t type 9 | func fromStatT(s *syscall.Stat_t) (*StatT, error) { 10 | return &StatT{size: s.Size, 11 | mode: uint32(s.Mode), 12 | uid: s.Uid, 13 | gid: s.Gid, 14 | rdev: uint64(s.Rdev), 15 | mtim: s.Mtim}, nil 16 | } 17 | -------------------------------------------------------------------------------- /docker/pkg/system/stat_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | // +build !windows 6 | 7 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 8 | 9 | import ( 10 | "syscall" 11 | ) 12 | 13 | // StatT type contains status of a file. It contains metadata 14 | // like permission, owner, group, size, etc about a file. 15 | type StatT struct { 16 | mode uint32 17 | uid uint32 18 | gid uint32 19 | rdev uint64 20 | size int64 21 | mtim syscall.Timespec 22 | } 23 | 24 | // Mode returns file's permission mode. 25 | func (s StatT) Mode() uint32 { 26 | return s.mode 27 | } 28 | 29 | // UID returns file's user id of owner. 30 | func (s StatT) UID() uint32 { 31 | return s.uid 32 | } 33 | 34 | // GID returns file's group id of owner. 35 | func (s StatT) GID() uint32 { 36 | return s.gid 37 | } 38 | 39 | // Rdev returns file's device ID (if it's special file). 40 | func (s StatT) Rdev() uint64 { 41 | return s.rdev 42 | } 43 | 44 | // Size returns file's size. 45 | func (s StatT) Size() int64 { 46 | return s.size 47 | } 48 | 49 | // Mtim returns file's last modification time. 50 | func (s StatT) Mtim() syscall.Timespec { 51 | return s.mtim 52 | } 53 | 54 | // IsDir reports whether s describes a directory. 55 | func (s StatT) IsDir() bool { 56 | return s.mode&syscall.S_IFDIR != 0 57 | } 58 | 59 | // Stat takes a path to a file and returns 60 | // a system.StatT type pertaining to that file. 61 | // 62 | // Throws an error if the file does not exist 63 | func Stat(path string) (*StatT, error) { 64 | s := &syscall.Stat_t{} 65 | if err := syscall.Stat(path, s); err != nil { 66 | return nil, err 67 | } 68 | return fromStatT(s) 69 | } 70 | -------------------------------------------------------------------------------- /docker/pkg/system/stat_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import ( 7 | "os" 8 | "time" 9 | ) 10 | 11 | // StatT type contains status of a file. It contains metadata 12 | // like permission, size, etc about a file. 13 | type StatT struct { 14 | mode os.FileMode 15 | size int64 16 | mtim time.Time 17 | } 18 | 19 | // Size returns file's size. 20 | func (s StatT) Size() int64 { 21 | return s.size 22 | } 23 | 24 | // Mode returns file's permission mode. 25 | func (s StatT) Mode() os.FileMode { 26 | return os.FileMode(s.mode) 27 | } 28 | 29 | // Mtim returns file's last modification time. 30 | func (s StatT) Mtim() time.Time { 31 | return time.Time(s.mtim) 32 | } 33 | 34 | // Stat takes a path to a file and returns 35 | // a system.StatT type pertaining to that file. 36 | // 37 | // Throws an error if the file does not exist 38 | func Stat(path string) (*StatT, error) { 39 | fi, err := os.Stat(path) 40 | if err != nil { 41 | return nil, err 42 | } 43 | return fromStatT(&fi) 44 | } 45 | 46 | // fromStatT converts a os.FileInfo type to a system.StatT type 47 | func fromStatT(fi *os.FileInfo) (*StatT, error) { 48 | return &StatT{ 49 | size: (*fi).Size(), 50 | mode: (*fi).Mode(), 51 | mtim: (*fi).ModTime()}, nil 52 | } 53 | -------------------------------------------------------------------------------- /docker/pkg/system/syscall_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build linux || freebsd 5 | // +build linux freebsd 6 | 7 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 8 | 9 | import "golang.org/x/sys/unix" 10 | 11 | // Unmount is a platform-specific helper function to call 12 | // the unmount syscall. 13 | func Unmount(dest string) error { 14 | return unix.Unmount(dest, 0) 15 | } 16 | 17 | // CommandLineToArgv should not be used on Unix. 18 | // It simply returns commandLine in the only element in the returned array. 19 | func CommandLineToArgv(commandLine string) ([]string, error) { 20 | return []string{commandLine}, nil 21 | } 22 | -------------------------------------------------------------------------------- /docker/pkg/system/umask.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | // +build !windows 6 | 7 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 8 | 9 | import ( 10 | "golang.org/x/sys/unix" 11 | ) 12 | 13 | // Umask sets current process's file mode creation mask to newmask 14 | // and returns oldmask. 15 | func Umask(newmask int) (oldmask int, err error) { 16 | return unix.Umask(newmask), nil 17 | } 18 | -------------------------------------------------------------------------------- /docker/pkg/system/umask_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | // Umask is not supported on the windows platform. 7 | func Umask(newmask int) (oldmask int, err error) { 8 | // should not be called on cli code path 9 | return 0, ErrNotSupportedPlatform 10 | } 11 | -------------------------------------------------------------------------------- /docker/pkg/system/utimes_freebsd.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import ( 7 | "syscall" 8 | "unsafe" 9 | 10 | "golang.org/x/sys/unix" 11 | ) 12 | 13 | // LUtimesNano is used to change access and modification time of the specified path. 14 | // It's used for symbol link file because unix.UtimesNano doesn't support a NOFOLLOW flag atm. 15 | func LUtimesNano(path string, ts []syscall.Timespec) error { 16 | var _path *byte 17 | _path, err := unix.BytePtrFromString(path) 18 | if err != nil { 19 | return err 20 | } 21 | 22 | if _, _, err := unix.Syscall(unix.SYS_LUTIMES, uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), 0); err != 0 && err != unix.ENOSYS { 23 | return err 24 | } 25 | 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /docker/pkg/system/utimes_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import ( 7 | "syscall" 8 | "unsafe" 9 | 10 | "golang.org/x/sys/unix" 11 | ) 12 | 13 | // LUtimesNano is used to change access and modification time of the specified path. 14 | // It's used for symbol link file because unix.UtimesNano doesn't support a NOFOLLOW flag atm. 15 | func LUtimesNano(path string, ts []syscall.Timespec) error { 16 | atFdCwd := unix.AT_FDCWD 17 | 18 | var _path *byte 19 | _path, err := unix.BytePtrFromString(path) 20 | if err != nil { 21 | return err 22 | } 23 | if _, _, err := unix.Syscall6(unix.SYS_UTIMENSAT, uintptr(atFdCwd), uintptr(unsafe.Pointer(_path)), uintptr(unsafe.Pointer(&ts[0])), unix.AT_SYMLINK_NOFOLLOW, 0, 0); err != 0 && err != unix.ENOSYS { 24 | return err 25 | } 26 | 27 | return nil 28 | } 29 | -------------------------------------------------------------------------------- /docker/pkg/system/utimes_unsupported.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !linux && !freebsd 5 | // +build !linux,!freebsd 6 | 7 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 8 | 9 | import "syscall" 10 | 11 | // LUtimesNano is only supported on linux and freebsd. 12 | func LUtimesNano(path string, ts []syscall.Timespec) error { 13 | return ErrNotSupportedPlatform 14 | } 15 | -------------------------------------------------------------------------------- /docker/pkg/system/xattrs_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 5 | 6 | import "golang.org/x/sys/unix" 7 | 8 | // Lgetxattr retrieves the value of the extended attribute identified by attr 9 | // and associated with the given path in the file system. 10 | // It will returns a nil slice and nil error if the xattr is not set. 11 | func Lgetxattr(path string, attr string) ([]byte, error) { 12 | dest := make([]byte, 128) 13 | sz, errno := unix.Lgetxattr(path, attr, dest) 14 | if errno == unix.ENODATA { 15 | return nil, nil 16 | } 17 | if errno == unix.ERANGE { 18 | dest = make([]byte, sz) 19 | sz, errno = unix.Lgetxattr(path, attr, dest) 20 | } 21 | if errno != nil { 22 | return nil, errno 23 | } 24 | 25 | return dest[:sz], nil 26 | } 27 | 28 | // Lsetxattr sets the value of the extended attribute identified by attr 29 | // and associated with the given path in the file system. 30 | func Lsetxattr(path string, attr string, data []byte, flags int) error { 31 | return unix.Lsetxattr(path, attr, data, flags) 32 | } 33 | -------------------------------------------------------------------------------- /docker/pkg/system/xattrs_unsupported.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !linux 5 | // +build !linux 6 | 7 | package system // import "github.com/ory/dockertest/v3/docker/pkg/system" 8 | 9 | // Lgetxattr is not supported on platforms other than linux. 10 | func Lgetxattr(path string, attr string) ([]byte, error) { 11 | return nil, ErrNotSupportedPlatform 12 | } 13 | 14 | // Lsetxattr is not supported on platforms other than linux. 15 | func Lsetxattr(path string, attr string, data []byte, flags int) error { 16 | return ErrNotSupportedPlatform 17 | } 18 | -------------------------------------------------------------------------------- /docker/registry_auth.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Copyright 2013 go-dockerclient authors. All rights reserved. 5 | // Use of this source code is governed by a BSD-style 6 | // license that can be found in the LICENSE file. 7 | 8 | package docker 9 | 10 | type registryAuth interface { 11 | isEmpty() bool 12 | headerKey() string 13 | } 14 | -------------------------------------------------------------------------------- /docker/signal.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Copyright 2014 go-dockerclient authors. All rights reserved. 5 | // Use of this source code is governed by a BSD-style 6 | // license that can be found in the LICENSE file. 7 | 8 | package docker 9 | 10 | // Signal represents a signal that can be send to the container on 11 | // KillContainer call. 12 | type Signal int 13 | 14 | // These values represent all signals available on Linux, where containers will 15 | // be running. 16 | const ( 17 | SIGABRT = Signal(0x6) 18 | SIGALRM = Signal(0xe) 19 | SIGBUS = Signal(0x7) 20 | SIGCHLD = Signal(0x11) 21 | SIGCLD = Signal(0x11) 22 | SIGCONT = Signal(0x12) 23 | SIGFPE = Signal(0x8) 24 | SIGHUP = Signal(0x1) 25 | SIGILL = Signal(0x4) 26 | SIGINT = Signal(0x2) 27 | SIGIO = Signal(0x1d) 28 | SIGIOT = Signal(0x6) 29 | SIGKILL = Signal(0x9) 30 | SIGPIPE = Signal(0xd) 31 | SIGPOLL = Signal(0x1d) 32 | SIGPROF = Signal(0x1b) 33 | SIGPWR = Signal(0x1e) 34 | SIGQUIT = Signal(0x3) 35 | SIGSEGV = Signal(0xb) 36 | SIGSTKFLT = Signal(0x10) 37 | SIGSTOP = Signal(0x13) 38 | SIGSYS = Signal(0x1f) 39 | SIGTERM = Signal(0xf) 40 | SIGTRAP = Signal(0x5) 41 | SIGTSTP = Signal(0x14) 42 | SIGTTIN = Signal(0x15) 43 | SIGTTOU = Signal(0x16) 44 | SIGUNUSED = Signal(0x1f) 45 | SIGURG = Signal(0x17) 46 | SIGUSR1 = Signal(0xa) 47 | SIGUSR2 = Signal(0xc) 48 | SIGVTALRM = Signal(0x1a) 49 | SIGWINCH = Signal(0x1c) 50 | SIGXCPU = Signal(0x18) 51 | SIGXFSZ = Signal(0x19) 52 | ) 53 | -------------------------------------------------------------------------------- /docker/types/auth.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types // import "github.com/ory/dockertest/v3/docker/types" 5 | 6 | // AuthConfig contains authorization information for connecting to a Registry 7 | type AuthConfig struct { 8 | Username string `json:"username,omitempty"` 9 | Password string `json:"password,omitempty"` 10 | Auth string `json:"auth,omitempty"` 11 | 12 | // Email is an optional value associated with the username. 13 | // This field is deprecated and will be removed in a later 14 | // version of docker. 15 | Email string `json:"email,omitempty"` 16 | 17 | ServerAddress string `json:"serveraddress,omitempty"` 18 | 19 | // IdentityToken is used to authenticate the user and get 20 | // an access token for the registry. 21 | IdentityToken string `json:"identitytoken,omitempty"` 22 | 23 | // RegistryToken is a bearer token to be sent to a registry 24 | RegistryToken string `json:"registrytoken,omitempty"` 25 | } 26 | -------------------------------------------------------------------------------- /docker/types/blkiodev/blkio.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package blkiodev // import "github.com/ory/dockertest/v3/docker/types/blkiodev" 5 | 6 | import "fmt" 7 | 8 | // WeightDevice is a structure that holds device:weight pair 9 | type WeightDevice struct { 10 | Path string 11 | Weight uint16 12 | } 13 | 14 | func (w *WeightDevice) String() string { 15 | return fmt.Sprintf("%s:%d", w.Path, w.Weight) 16 | } 17 | 18 | // ThrottleDevice is a structure that holds device:rate_per_second pair 19 | type ThrottleDevice struct { 20 | Path string 21 | Rate uint64 22 | } 23 | 24 | func (t *ThrottleDevice) String() string { 25 | return fmt.Sprintf("%s:%d", t.Path, t.Rate) 26 | } 27 | -------------------------------------------------------------------------------- /docker/types/configs.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types // import "github.com/ory/dockertest/v3/docker/types" 5 | 6 | import ( 7 | "github.com/ory/dockertest/v3/docker/types/container" 8 | "github.com/ory/dockertest/v3/docker/types/network" 9 | ) 10 | 11 | // configs holds structs used for internal communication between the 12 | // frontend (such as an http server) and the backend (such as the 13 | // docker daemon). 14 | 15 | // ContainerCreateConfig is the parameter set to ContainerCreate() 16 | type ContainerCreateConfig struct { 17 | Name string 18 | Config *container.Config 19 | HostConfig *container.HostConfig 20 | NetworkingConfig *network.NetworkingConfig 21 | AdjustCPUShares bool 22 | } 23 | 24 | // ContainerRmConfig holds arguments for the container remove 25 | // operation. This struct is used to tell the backend what operations 26 | // to perform. 27 | type ContainerRmConfig struct { 28 | ForceRemove, RemoveVolume, RemoveLink bool 29 | } 30 | 31 | // ExecConfig is a small subset of the Config struct that holds the configuration 32 | // for the exec feature of docker. 33 | type ExecConfig struct { 34 | User string // User that will run the command 35 | Privileged bool // Is the container in privileged mode 36 | Tty bool // Attach standard streams to a tty. 37 | AttachStdin bool // Attach the standard input, makes possible user interaction 38 | AttachStderr bool // Attach the standard error 39 | AttachStdout bool // Attach the standard output 40 | Detach bool // Execute in detach mode 41 | DetachKeys string // Escape keys for detach 42 | Env []string // Environment variables 43 | WorkingDir string // Working directory 44 | Cmd []string // Execution commands and args 45 | } 46 | 47 | // PluginRmConfig holds arguments for plugin remove. 48 | type PluginRmConfig struct { 49 | ForceRemove bool 50 | } 51 | 52 | // PluginEnableConfig holds arguments for plugin enable 53 | type PluginEnableConfig struct { 54 | Timeout int 55 | } 56 | 57 | // PluginDisableConfig holds arguments for plugin disable. 58 | type PluginDisableConfig struct { 59 | ForceDisable bool 60 | } 61 | -------------------------------------------------------------------------------- /docker/types/container/container_changes.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package container 5 | 6 | // ---------------------------------------------------------------------------- 7 | // DO NOT EDIT THIS FILE 8 | // This file was generated by `swagger generate operation` 9 | // 10 | // See hack/generate-swagger-api.sh 11 | // ---------------------------------------------------------------------------- 12 | 13 | // ContainerChangeResponseItem change item in response to ContainerChanges operation 14 | // swagger:model ContainerChangeResponseItem 15 | type ContainerChangeResponseItem struct { 16 | 17 | // Kind of change 18 | // Required: true 19 | Kind uint8 `json:"Kind"` 20 | 21 | // Path to file that has changed 22 | // Required: true 23 | Path string `json:"Path"` 24 | } 25 | -------------------------------------------------------------------------------- /docker/types/container/container_create.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package container 5 | 6 | // ---------------------------------------------------------------------------- 7 | // DO NOT EDIT THIS FILE 8 | // This file was generated by `swagger generate operation` 9 | // 10 | // See hack/generate-swagger-api.sh 11 | // ---------------------------------------------------------------------------- 12 | 13 | // ContainerCreateCreatedBody OK response to ContainerCreate operation 14 | // swagger:model ContainerCreateCreatedBody 15 | type ContainerCreateCreatedBody struct { 16 | 17 | // The ID of the created container 18 | // Required: true 19 | ID string `json:"Id"` 20 | 21 | // Warnings encountered when creating the container 22 | // Required: true 23 | Warnings []string `json:"Warnings"` 24 | } 25 | -------------------------------------------------------------------------------- /docker/types/container/container_top.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package container 5 | 6 | // ---------------------------------------------------------------------------- 7 | // DO NOT EDIT THIS FILE 8 | // This file was generated by `swagger generate operation` 9 | // 10 | // See hack/generate-swagger-api.sh 11 | // ---------------------------------------------------------------------------- 12 | 13 | // ContainerTopOKBody OK response to ContainerTop operation 14 | // swagger:model ContainerTopOKBody 15 | type ContainerTopOKBody struct { 16 | 17 | // Each process running in the container, where each is process is an array of values corresponding to the titles 18 | // Required: true 19 | Processes [][]string `json:"Processes"` 20 | 21 | // The ps column titles 22 | // Required: true 23 | Titles []string `json:"Titles"` 24 | } 25 | -------------------------------------------------------------------------------- /docker/types/container/container_update.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package container 5 | 6 | // ---------------------------------------------------------------------------- 7 | // DO NOT EDIT THIS FILE 8 | // This file was generated by `swagger generate operation` 9 | // 10 | // See hack/generate-swagger-api.sh 11 | // ---------------------------------------------------------------------------- 12 | 13 | // ContainerUpdateOKBody OK response to ContainerUpdate operation 14 | // swagger:model ContainerUpdateOKBody 15 | type ContainerUpdateOKBody struct { 16 | 17 | // warnings 18 | // Required: true 19 | Warnings []string `json:"Warnings"` 20 | } 21 | -------------------------------------------------------------------------------- /docker/types/container/container_wait.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package container 5 | 6 | // ---------------------------------------------------------------------------- 7 | // DO NOT EDIT THIS FILE 8 | // This file was generated by `swagger generate operation` 9 | // 10 | // See hack/generate-swagger-api.sh 11 | // ---------------------------------------------------------------------------- 12 | 13 | // ContainerWaitOKBodyError container waiting error, if any 14 | // swagger:model ContainerWaitOKBodyError 15 | type ContainerWaitOKBodyError struct { 16 | 17 | // Details of an error 18 | Message string `json:"Message,omitempty"` 19 | } 20 | 21 | // ContainerWaitOKBody OK response to ContainerWait operation 22 | // swagger:model ContainerWaitOKBody 23 | type ContainerWaitOKBody struct { 24 | 25 | // error 26 | // Required: true 27 | Error *ContainerWaitOKBodyError `json:"Error"` 28 | 29 | // Exit code of the container 30 | // Required: true 31 | StatusCode int64 `json:"StatusCode"` 32 | } 33 | -------------------------------------------------------------------------------- /docker/types/container/hostconfig_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | // +build !windows 6 | 7 | package container // import "github.com/ory/dockertest/v3/docker/types/container" 8 | 9 | // IsValid indicates if an isolation technology is valid 10 | func (i Isolation) IsValid() bool { 11 | return i.IsDefault() 12 | } 13 | 14 | // NetworkName returns the name of the network stack. 15 | func (n NetworkMode) NetworkName() string { 16 | if n.IsBridge() { 17 | return "bridge" 18 | } else if n.IsHost() { 19 | return "host" 20 | } else if n.IsContainer() { 21 | return "container" 22 | } else if n.IsNone() { 23 | return "none" 24 | } else if n.IsDefault() { 25 | return "default" 26 | } else if n.IsUserDefined() { 27 | return n.UserDefined() 28 | } 29 | return "" 30 | } 31 | 32 | // IsBridge indicates whether container uses the bridge network stack 33 | func (n NetworkMode) IsBridge() bool { 34 | return n == "bridge" 35 | } 36 | 37 | // IsHost indicates whether container uses the host network stack. 38 | func (n NetworkMode) IsHost() bool { 39 | return n == "host" 40 | } 41 | 42 | // IsUserDefined indicates user-created network 43 | func (n NetworkMode) IsUserDefined() bool { 44 | return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() 45 | } 46 | -------------------------------------------------------------------------------- /docker/types/container/hostconfig_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package container // import "github.com/ory/dockertest/v3/docker/types/container" 5 | 6 | // IsBridge indicates whether container uses the bridge network stack 7 | // in windows it is given the name NAT 8 | func (n NetworkMode) IsBridge() bool { 9 | return n == "nat" 10 | } 11 | 12 | // IsHost indicates whether container uses the host network stack. 13 | // returns false as this is not supported by windows 14 | func (n NetworkMode) IsHost() bool { 15 | return false 16 | } 17 | 18 | // IsUserDefined indicates user-created network 19 | func (n NetworkMode) IsUserDefined() bool { 20 | return !n.IsDefault() && !n.IsNone() && !n.IsBridge() && !n.IsContainer() 21 | } 22 | 23 | // IsValid indicates if an isolation technology is valid 24 | func (i Isolation) IsValid() bool { 25 | return i.IsDefault() || i.IsHyperV() || i.IsProcess() 26 | } 27 | 28 | // NetworkName returns the name of the network stack. 29 | func (n NetworkMode) NetworkName() string { 30 | if n.IsDefault() { 31 | return "default" 32 | } else if n.IsBridge() { 33 | return "nat" 34 | } else if n.IsNone() { 35 | return "none" 36 | } else if n.IsContainer() { 37 | return "container" 38 | } else if n.IsUserDefined() { 39 | return n.UserDefined() 40 | } 41 | 42 | return "" 43 | } 44 | -------------------------------------------------------------------------------- /docker/types/container/waitcondition.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package container // import "github.com/ory/dockertest/v3/docker/types/container" 5 | 6 | // WaitCondition is a type used to specify a container state for which 7 | // to wait. 8 | type WaitCondition string 9 | 10 | // Possible WaitCondition Values. 11 | // 12 | // WaitConditionNotRunning (default) is used to wait for any of the non-running 13 | // states: "created", "exited", "dead", "removing", or "removed". 14 | // 15 | // WaitConditionNextExit is used to wait for the next time the state changes 16 | // to a non-running state. If the state is currently "created" or "exited", 17 | // this would cause Wait() to block until either the container runs and exits 18 | // or is removed. 19 | // 20 | // WaitConditionRemoved is used to wait for the container to be removed. 21 | const ( 22 | WaitConditionNotRunning WaitCondition = "not-running" 23 | WaitConditionNextExit WaitCondition = "next-exit" 24 | WaitConditionRemoved WaitCondition = "removed" 25 | ) 26 | -------------------------------------------------------------------------------- /docker/types/error_response.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types 5 | 6 | // This file was generated by the swagger tool. 7 | // Editing this file might prove futile when you re-run the swagger generate command 8 | 9 | // ErrorResponse Represents an error. 10 | // swagger:model ErrorResponse 11 | type ErrorResponse struct { 12 | 13 | // The error message. 14 | // Required: true 15 | Message string `json:"message"` 16 | } 17 | -------------------------------------------------------------------------------- /docker/types/filters/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package filters // import "github.com/ory/dockertest/v3/docker/types/filters" 5 | 6 | func ExampleArgs_MatchKVList() { 7 | args := NewArgs( 8 | Arg("label", "image=foo"), 9 | Arg("label", "state=running")) 10 | 11 | // returns true because there are no values for bogus 12 | args.MatchKVList("bogus", nil) 13 | 14 | // returns false because there are no sources 15 | args.MatchKVList("label", nil) 16 | 17 | // returns true because all sources are matched 18 | args.MatchKVList("label", map[string]string{ 19 | "image": "foo", 20 | "state": "running", 21 | }) 22 | 23 | // returns false because the values do not match 24 | args.MatchKVList("label", map[string]string{ 25 | "image": "other", 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /docker/types/graph_driver_data.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types 5 | 6 | // This file was generated by the swagger tool. 7 | // Editing this file might prove futile when you re-run the swagger generate command 8 | 9 | // GraphDriverData Information about a container's graph driver. 10 | // swagger:model GraphDriverData 11 | type GraphDriverData struct { 12 | 13 | // data 14 | // Required: true 15 | Data map[string]string `json:"Data"` 16 | 17 | // name 18 | // Required: true 19 | Name string `json:"Name"` 20 | } 21 | -------------------------------------------------------------------------------- /docker/types/id_response.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types 5 | 6 | // This file was generated by the swagger tool. 7 | // Editing this file might prove futile when you re-run the swagger generate command 8 | 9 | // IDResponse Response to an API call that returns just an Id 10 | // swagger:model IdResponse 11 | type IDResponse struct { 12 | 13 | // The id of the newly created object. 14 | // Required: true 15 | ID string `json:"Id"` 16 | } 17 | -------------------------------------------------------------------------------- /docker/types/image_delete_response_item.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types 5 | 6 | // This file was generated by the swagger tool. 7 | // Editing this file might prove futile when you re-run the swagger generate command 8 | 9 | // ImageDeleteResponseItem image delete response item 10 | // swagger:model ImageDeleteResponseItem 11 | type ImageDeleteResponseItem struct { 12 | 13 | // The image ID of an image that was deleted 14 | Deleted string `json:"Deleted,omitempty"` 15 | 16 | // The image ID of an image that was untagged 17 | Untagged string `json:"Untagged,omitempty"` 18 | } 19 | -------------------------------------------------------------------------------- /docker/types/image_summary.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types 5 | 6 | // This file was generated by the swagger tool. 7 | // Editing this file might prove futile when you re-run the swagger generate command 8 | 9 | // ImageSummary image summary 10 | // swagger:model ImageSummary 11 | type ImageSummary struct { 12 | 13 | // containers 14 | // Required: true 15 | Containers int64 `json:"Containers"` 16 | 17 | // created 18 | // Required: true 19 | Created int64 `json:"Created"` 20 | 21 | // Id 22 | // Required: true 23 | ID string `json:"Id"` 24 | 25 | // labels 26 | // Required: true 27 | Labels map[string]string `json:"Labels"` 28 | 29 | // parent Id 30 | // Required: true 31 | ParentID string `json:"ParentId"` 32 | 33 | // repo digests 34 | // Required: true 35 | RepoDigests []string `json:"RepoDigests"` 36 | 37 | // repo tags 38 | // Required: true 39 | RepoTags []string `json:"RepoTags"` 40 | 41 | // shared size 42 | // Required: true 43 | SharedSize int64 `json:"SharedSize"` 44 | 45 | // size 46 | // Required: true 47 | Size int64 `json:"Size"` 48 | 49 | // virtual size 50 | // Required: true 51 | VirtualSize int64 `json:"VirtualSize"` 52 | } 53 | -------------------------------------------------------------------------------- /docker/types/network/network.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package network // import "github.com/ory/dockertest/v3/docker/types/network" 5 | 6 | // Address represents an IP address 7 | type Address struct { 8 | Addr string 9 | PrefixLen int 10 | } 11 | 12 | // IPAM represents IP Address Management 13 | type IPAM struct { 14 | Driver string 15 | Options map[string]string //Per network IPAM driver options 16 | Config []IPAMConfig 17 | } 18 | 19 | // IPAMConfig represents IPAM configurations 20 | type IPAMConfig struct { 21 | Subnet string `json:",omitempty"` 22 | IPRange string `json:",omitempty"` 23 | Gateway string `json:",omitempty"` 24 | AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"` 25 | } 26 | 27 | // EndpointIPAMConfig represents IPAM configurations for the endpoint 28 | type EndpointIPAMConfig struct { 29 | IPv4Address string `json:",omitempty"` 30 | IPv6Address string `json:",omitempty"` 31 | LinkLocalIPs []string `json:",omitempty"` 32 | } 33 | 34 | // Copy makes a copy of the endpoint ipam config 35 | func (cfg *EndpointIPAMConfig) Copy() *EndpointIPAMConfig { 36 | cfgCopy := *cfg 37 | cfgCopy.LinkLocalIPs = make([]string, 0, len(cfg.LinkLocalIPs)) 38 | cfgCopy.LinkLocalIPs = append(cfgCopy.LinkLocalIPs, cfg.LinkLocalIPs...) 39 | return &cfgCopy 40 | } 41 | 42 | // PeerInfo represents one peer of an overlay network 43 | type PeerInfo struct { 44 | Name string 45 | IP string 46 | } 47 | 48 | // EndpointSettings stores the network endpoint details 49 | type EndpointSettings struct { 50 | // Configurations 51 | IPAMConfig *EndpointIPAMConfig 52 | Links []string 53 | Aliases []string 54 | // Operational data 55 | NetworkID string 56 | EndpointID string 57 | Gateway string 58 | IPAddress string 59 | IPPrefixLen int 60 | IPv6Gateway string 61 | GlobalIPv6Address string 62 | GlobalIPv6PrefixLen int 63 | MacAddress string 64 | DriverOpts map[string]string 65 | } 66 | 67 | // Task carries the information about one backend task 68 | type Task struct { 69 | Name string 70 | EndpointID string 71 | EndpointIP string 72 | Info map[string]string 73 | } 74 | 75 | // ServiceInfo represents service parameters with the list of service's tasks 76 | type ServiceInfo struct { 77 | VIP string 78 | Ports []string 79 | LocalLBIndex int 80 | Tasks []Task 81 | } 82 | 83 | // Copy makes a deep copy of `EndpointSettings` 84 | func (es *EndpointSettings) Copy() *EndpointSettings { 85 | epCopy := *es 86 | if es.IPAMConfig != nil { 87 | epCopy.IPAMConfig = es.IPAMConfig.Copy() 88 | } 89 | 90 | if es.Links != nil { 91 | links := make([]string, 0, len(es.Links)) 92 | epCopy.Links = append(links, es.Links...) 93 | } 94 | 95 | if es.Aliases != nil { 96 | aliases := make([]string, 0, len(es.Aliases)) 97 | epCopy.Aliases = append(aliases, es.Aliases...) 98 | } 99 | return &epCopy 100 | } 101 | 102 | // NetworkingConfig represents the container's networking configuration for each of its interfaces 103 | // Carries the networking configs specified in the `docker run` and `docker network connect` commands 104 | type NetworkingConfig struct { 105 | EndpointsConfig map[string]*EndpointSettings // Endpoint configs for each connecting network 106 | } 107 | 108 | // ConfigReference specifies the source which provides a network's configuration 109 | type ConfigReference struct { 110 | Network string 111 | } 112 | -------------------------------------------------------------------------------- /docker/types/plugin_device.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types 5 | 6 | // This file was generated by the swagger tool. 7 | // Editing this file might prove futile when you re-run the swagger generate command 8 | 9 | // PluginDevice plugin device 10 | // swagger:model PluginDevice 11 | type PluginDevice struct { 12 | 13 | // description 14 | // Required: true 15 | Description string `json:"Description"` 16 | 17 | // name 18 | // Required: true 19 | Name string `json:"Name"` 20 | 21 | // path 22 | // Required: true 23 | Path *string `json:"Path"` 24 | 25 | // settable 26 | // Required: true 27 | Settable []string `json:"Settable"` 28 | } 29 | -------------------------------------------------------------------------------- /docker/types/plugin_env.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types 5 | 6 | // This file was generated by the swagger tool. 7 | // Editing this file might prove futile when you re-run the swagger generate command 8 | 9 | // PluginEnv plugin env 10 | // swagger:model PluginEnv 11 | type PluginEnv struct { 12 | 13 | // description 14 | // Required: true 15 | Description string `json:"Description"` 16 | 17 | // name 18 | // Required: true 19 | Name string `json:"Name"` 20 | 21 | // settable 22 | // Required: true 23 | Settable []string `json:"Settable"` 24 | 25 | // value 26 | // Required: true 27 | Value *string `json:"Value"` 28 | } 29 | -------------------------------------------------------------------------------- /docker/types/plugin_interface_type.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types 5 | 6 | // This file was generated by the swagger tool. 7 | // Editing this file might prove futile when you re-run the swagger generate command 8 | 9 | // PluginInterfaceType plugin interface type 10 | // swagger:model PluginInterfaceType 11 | type PluginInterfaceType struct { 12 | 13 | // capability 14 | // Required: true 15 | Capability string `json:"Capability"` 16 | 17 | // prefix 18 | // Required: true 19 | Prefix string `json:"Prefix"` 20 | 21 | // version 22 | // Required: true 23 | Version string `json:"Version"` 24 | } 25 | -------------------------------------------------------------------------------- /docker/types/plugin_mount.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types 5 | 6 | // This file was generated by the swagger tool. 7 | // Editing this file might prove futile when you re-run the swagger generate command 8 | 9 | // PluginMount plugin mount 10 | // swagger:model PluginMount 11 | type PluginMount struct { 12 | 13 | // description 14 | // Required: true 15 | Description string `json:"Description"` 16 | 17 | // destination 18 | // Required: true 19 | Destination string `json:"Destination"` 20 | 21 | // name 22 | // Required: true 23 | Name string `json:"Name"` 24 | 25 | // options 26 | // Required: true 27 | Options []string `json:"Options"` 28 | 29 | // settable 30 | // Required: true 31 | Settable []string `json:"Settable"` 32 | 33 | // source 34 | // Required: true 35 | Source *string `json:"Source"` 36 | 37 | // type 38 | // Required: true 39 | Type string `json:"Type"` 40 | } 41 | -------------------------------------------------------------------------------- /docker/types/plugin_responses.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types // import "github.com/ory/dockertest/v3/docker/types" 5 | 6 | import ( 7 | "encoding/json" 8 | "fmt" 9 | "sort" 10 | ) 11 | 12 | // PluginsListResponse contains the response for the Engine API 13 | type PluginsListResponse []*Plugin 14 | 15 | // UnmarshalJSON implements json.Unmarshaler for PluginInterfaceType 16 | func (t *PluginInterfaceType) UnmarshalJSON(p []byte) error { 17 | versionIndex := len(p) 18 | prefixIndex := 0 19 | if len(p) < 2 || p[0] != '"' || p[len(p)-1] != '"' { 20 | return fmt.Errorf("%q is not a plugin interface type", p) 21 | } 22 | p = p[1 : len(p)-1] 23 | loop: 24 | for i, b := range p { 25 | switch b { 26 | case '.': 27 | prefixIndex = i 28 | case '/': 29 | versionIndex = i 30 | break loop 31 | } 32 | } 33 | t.Prefix = string(p[:prefixIndex]) 34 | t.Capability = string(p[prefixIndex+1 : versionIndex]) 35 | if versionIndex < len(p) { 36 | t.Version = string(p[versionIndex+1:]) 37 | } 38 | return nil 39 | } 40 | 41 | // MarshalJSON implements json.Marshaler for PluginInterfaceType 42 | func (t *PluginInterfaceType) MarshalJSON() ([]byte, error) { 43 | return json.Marshal(t.String()) 44 | } 45 | 46 | // String implements fmt.Stringer for PluginInterfaceType 47 | func (t PluginInterfaceType) String() string { 48 | return fmt.Sprintf("%s.%s/%s", t.Prefix, t.Capability, t.Version) 49 | } 50 | 51 | // PluginPrivilege describes a permission the user has to accept 52 | // upon installing a plugin. 53 | type PluginPrivilege struct { 54 | Name string 55 | Description string 56 | Value []string 57 | } 58 | 59 | // PluginPrivileges is a list of PluginPrivilege 60 | type PluginPrivileges []PluginPrivilege 61 | 62 | func (s PluginPrivileges) Len() int { 63 | return len(s) 64 | } 65 | 66 | func (s PluginPrivileges) Less(i, j int) bool { 67 | return s[i].Name < s[j].Name 68 | } 69 | 70 | func (s PluginPrivileges) Swap(i, j int) { 71 | sort.Strings(s[i].Value) 72 | sort.Strings(s[j].Value) 73 | s[i], s[j] = s[j], s[i] 74 | } 75 | -------------------------------------------------------------------------------- /docker/types/port.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types 5 | 6 | // This file was generated by the swagger tool. 7 | // Editing this file might prove futile when you re-run the swagger generate command 8 | 9 | // Port An open port on a container 10 | // swagger:model Port 11 | type Port struct { 12 | 13 | // IP 14 | IP string `json:"IP,omitempty"` 15 | 16 | // Port on the container 17 | // Required: true 18 | PrivatePort uint16 `json:"PrivatePort"` 19 | 20 | // Port exposed on the host 21 | PublicPort uint16 `json:"PublicPort,omitempty"` 22 | 23 | // type 24 | // Required: true 25 | Type string `json:"Type"` 26 | } 27 | -------------------------------------------------------------------------------- /docker/types/registry/authenticate.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package registry // import "github.com/ory/dockertest/v3/docker/types/registry" 5 | 6 | // ---------------------------------------------------------------------------- 7 | // DO NOT EDIT THIS FILE 8 | // This file was generated by `swagger generate operation` 9 | // 10 | // See hack/generate-swagger-api.sh 11 | // ---------------------------------------------------------------------------- 12 | 13 | // AuthenticateOKBody authenticate o k body 14 | // swagger:model AuthenticateOKBody 15 | type AuthenticateOKBody struct { 16 | 17 | // An opaque token used to authenticate a user after a successful login 18 | // Required: true 19 | IdentityToken string `json:"IdentityToken"` 20 | 21 | // The status of the authentication 22 | // Required: true 23 | Status string `json:"Status"` 24 | } 25 | -------------------------------------------------------------------------------- /docker/types/seccomp.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types // import "github.com/ory/dockertest/v3/docker/types" 5 | 6 | // Seccomp represents the config for a seccomp profile for syscall restriction. 7 | type Seccomp struct { 8 | DefaultAction Action `json:"defaultAction"` 9 | // Architectures is kept to maintain backward compatibility with the old 10 | // seccomp profile. 11 | Architectures []Arch `json:"architectures,omitempty"` 12 | ArchMap []Architecture `json:"archMap,omitempty"` 13 | Syscalls []*Syscall `json:"syscalls"` 14 | } 15 | 16 | // Architecture is used to represent a specific architecture 17 | // and its sub-architectures 18 | type Architecture struct { 19 | Arch Arch `json:"architecture"` 20 | SubArches []Arch `json:"subArchitectures"` 21 | } 22 | 23 | // Arch used for architectures 24 | type Arch string 25 | 26 | // Additional architectures permitted to be used for system calls 27 | // By default only the native architecture of the kernel is permitted 28 | const ( 29 | ArchX86 Arch = "SCMP_ARCH_X86" 30 | ArchX86_64 Arch = "SCMP_ARCH_X86_64" 31 | ArchX32 Arch = "SCMP_ARCH_X32" 32 | ArchARM Arch = "SCMP_ARCH_ARM" 33 | ArchAARCH64 Arch = "SCMP_ARCH_AARCH64" 34 | ArchMIPS Arch = "SCMP_ARCH_MIPS" 35 | ArchMIPS64 Arch = "SCMP_ARCH_MIPS64" 36 | ArchMIPS64N32 Arch = "SCMP_ARCH_MIPS64N32" 37 | ArchMIPSEL Arch = "SCMP_ARCH_MIPSEL" 38 | ArchMIPSEL64 Arch = "SCMP_ARCH_MIPSEL64" 39 | ArchMIPSEL64N32 Arch = "SCMP_ARCH_MIPSEL64N32" 40 | ArchPPC Arch = "SCMP_ARCH_PPC" 41 | ArchPPC64 Arch = "SCMP_ARCH_PPC64" 42 | ArchPPC64LE Arch = "SCMP_ARCH_PPC64LE" 43 | ArchS390 Arch = "SCMP_ARCH_S390" 44 | ArchS390X Arch = "SCMP_ARCH_S390X" 45 | ) 46 | 47 | // Action taken upon Seccomp rule match 48 | type Action string 49 | 50 | // Define actions for Seccomp rules 51 | const ( 52 | ActKill Action = "SCMP_ACT_KILL" 53 | ActTrap Action = "SCMP_ACT_TRAP" 54 | ActErrno Action = "SCMP_ACT_ERRNO" 55 | ActTrace Action = "SCMP_ACT_TRACE" 56 | ActAllow Action = "SCMP_ACT_ALLOW" 57 | ) 58 | 59 | // Operator used to match syscall arguments in Seccomp 60 | type Operator string 61 | 62 | // Define operators for syscall arguments in Seccomp 63 | const ( 64 | OpNotEqual Operator = "SCMP_CMP_NE" 65 | OpLessThan Operator = "SCMP_CMP_LT" 66 | OpLessEqual Operator = "SCMP_CMP_LE" 67 | OpEqualTo Operator = "SCMP_CMP_EQ" 68 | OpGreaterEqual Operator = "SCMP_CMP_GE" 69 | OpGreaterThan Operator = "SCMP_CMP_GT" 70 | OpMaskedEqual Operator = "SCMP_CMP_MASKED_EQ" 71 | ) 72 | 73 | // Arg used for matching specific syscall arguments in Seccomp 74 | type Arg struct { 75 | Index uint `json:"index"` 76 | Value uint64 `json:"value"` 77 | ValueTwo uint64 `json:"valueTwo"` 78 | Op Operator `json:"op"` 79 | } 80 | 81 | // Filter is used to conditionally apply Seccomp rules 82 | type Filter struct { 83 | Caps []string `json:"caps,omitempty"` 84 | Arches []string `json:"arches,omitempty"` 85 | } 86 | 87 | // Syscall is used to match a group of syscalls in Seccomp 88 | type Syscall struct { 89 | Name string `json:"name,omitempty"` 90 | Names []string `json:"names,omitempty"` 91 | Action Action `json:"action"` 92 | Args []*Arg `json:"args"` 93 | Comment string `json:"comment"` 94 | Includes Filter `json:"includes"` 95 | Excludes Filter `json:"excludes"` 96 | } 97 | -------------------------------------------------------------------------------- /docker/types/service_update_response.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types 5 | 6 | // This file was generated by the swagger tool. 7 | // Editing this file might prove futile when you re-run the swagger generate command 8 | 9 | // ServiceUpdateResponse service update response 10 | // swagger:model ServiceUpdateResponse 11 | type ServiceUpdateResponse struct { 12 | 13 | // Optional warning messages 14 | Warnings []string `json:"Warnings"` 15 | } 16 | -------------------------------------------------------------------------------- /docker/types/strslice/strslice.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package strslice // import "github.com/ory/dockertest/v3/docker/types/strslice" 5 | 6 | import "encoding/json" 7 | 8 | // StrSlice represents a string or an array of strings. 9 | // We need to override the json decoder to accept both options. 10 | type StrSlice []string 11 | 12 | // UnmarshalJSON decodes the byte slice whether it's a string or an array of 13 | // strings. This method is needed to implement json.Unmarshaler. 14 | func (e *StrSlice) UnmarshalJSON(b []byte) error { 15 | if len(b) == 0 { 16 | // With no input, we preserve the existing value by returning nil and 17 | // leaving the target alone. This allows defining default values for 18 | // the type. 19 | return nil 20 | } 21 | 22 | p := make([]string, 0, 1) 23 | if err := json.Unmarshal(b, &p); err != nil { 24 | var s string 25 | if err := json.Unmarshal(b, &s); err != nil { 26 | return err 27 | } 28 | p = append(p, s) 29 | } 30 | 31 | *e = p 32 | return nil 33 | } 34 | -------------------------------------------------------------------------------- /docker/types/strslice/strslice_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package strslice // import "github.com/ory/dockertest/v3/docker/types/strslice" 5 | 6 | import ( 7 | "encoding/json" 8 | "reflect" 9 | "testing" 10 | ) 11 | 12 | func TestStrSliceMarshalJSON(t *testing.T) { 13 | for _, testcase := range []struct { 14 | input StrSlice 15 | expected string 16 | }{ 17 | // MADNESS(stevvooe): No clue why nil would be "" but empty would be 18 | // "null". Had to make a change here that may affect compatibility. 19 | {input: nil, expected: "null"}, 20 | {StrSlice{}, "[]"}, 21 | {StrSlice{"/bin/sh", "-c", "echo"}, `["/bin/sh","-c","echo"]`}, 22 | } { 23 | data, err := json.Marshal(testcase.input) 24 | if err != nil { 25 | t.Fatal(err) 26 | } 27 | if string(data) != testcase.expected { 28 | t.Fatalf("%#v: expected %v, got %v", testcase.input, testcase.expected, string(data)) 29 | } 30 | } 31 | } 32 | 33 | func TestStrSliceUnmarshalJSON(t *testing.T) { 34 | parts := map[string][]string{ 35 | "": {"default", "values"}, 36 | "[]": {}, 37 | `["/bin/sh","-c","echo"]`: {"/bin/sh", "-c", "echo"}, 38 | } 39 | for json, expectedParts := range parts { 40 | strs := StrSlice{"default", "values"} 41 | if err := strs.UnmarshalJSON([]byte(json)); err != nil { 42 | t.Fatal(err) 43 | } 44 | 45 | actualParts := []string(strs) 46 | if !reflect.DeepEqual(actualParts, expectedParts) { 47 | t.Fatalf("%#v: expected %v, got %v", json, expectedParts, actualParts) 48 | } 49 | 50 | } 51 | } 52 | 53 | func TestStrSliceUnmarshalString(t *testing.T) { 54 | var e StrSlice 55 | echo, err := json.Marshal("echo") 56 | if err != nil { 57 | t.Fatal(err) 58 | } 59 | if err := json.Unmarshal(echo, &e); err != nil { 60 | t.Fatal(err) 61 | } 62 | 63 | if len(e) != 1 { 64 | t.Fatalf("expected 1 element after unmarshal: %q", e) 65 | } 66 | 67 | if e[0] != "echo" { 68 | t.Fatalf("expected `echo`, got: %q", e[0]) 69 | } 70 | } 71 | 72 | func TestStrSliceUnmarshalSlice(t *testing.T) { 73 | var e StrSlice 74 | echo, err := json.Marshal([]string{"echo"}) 75 | if err != nil { 76 | t.Fatal(err) 77 | } 78 | if err := json.Unmarshal(echo, &e); err != nil { 79 | t.Fatal(err) 80 | } 81 | 82 | if len(e) != 1 { 83 | t.Fatalf("expected 1 element after unmarshal: %q", e) 84 | } 85 | 86 | if e[0] != "echo" { 87 | t.Fatalf("expected `echo`, got: %q", e[0]) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /docker/types/versions/README.md: -------------------------------------------------------------------------------- 1 | # Legacy API type versions 2 | 3 | This package includes types for legacy API versions. The stable version of the 4 | API types live in `api/types/*.go`. 5 | 6 | Consider moving a type here when you need to keep backwards compatibility in the 7 | API. This legacy types are organized by the latest API version they appear in. 8 | For instance, types in the `v1p19` package are valid for API versions below or 9 | equal `1.19`. Types in the `v1p20` package are valid for the API version `1.20`, 10 | since the versions below that will use the legacy types in `v1p19`. 11 | 12 | ## Package name conventions 13 | 14 | The package name convention is to use `v` as a prefix for the version number and 15 | `p`(patch) as a separator. We use this nomenclature due to a few restrictions in 16 | the Go package name convention: 17 | 18 | 1. We cannot use `.` because it's interpreted by the language, think of 19 | `v1.20.CallFunction`. 20 | 2. We cannot use `_` because golint complains about it. The code is actually 21 | valid, but it looks probably more weird: `v1_20.CallFunction`. 22 | 23 | For instance, if you want to modify a type that was available in the version 24 | `1.21` of the API but it will have different fields in the version `1.22`, you 25 | want to create a new package under `api/types/versions/v1p21`. 26 | -------------------------------------------------------------------------------- /docker/types/versions/compare.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package versions // import "github.com/ory/dockertest/v3/docker/types/versions" 5 | 6 | import ( 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | // compare compares two version strings 12 | // returns -1 if v1 < v2, 1 if v1 > v2, 0 otherwise. 13 | func compare(v1, v2 string) int { 14 | var ( 15 | currTab = strings.Split(v1, ".") 16 | otherTab = strings.Split(v2, ".") 17 | ) 18 | 19 | max := len(currTab) 20 | if len(otherTab) > max { 21 | max = len(otherTab) 22 | } 23 | for i := 0; i < max; i++ { 24 | var currInt, otherInt int 25 | 26 | if len(currTab) > i { 27 | currInt, _ = strconv.Atoi(currTab[i]) 28 | } 29 | if len(otherTab) > i { 30 | otherInt, _ = strconv.Atoi(otherTab[i]) 31 | } 32 | if currInt > otherInt { 33 | return 1 34 | } 35 | if otherInt > currInt { 36 | return -1 37 | } 38 | } 39 | return 0 40 | } 41 | 42 | // LessThan checks if a version is less than another 43 | func LessThan(v, other string) bool { 44 | return compare(v, other) == -1 45 | } 46 | 47 | // LessThanOrEqualTo checks if a version is less than or equal to another 48 | func LessThanOrEqualTo(v, other string) bool { 49 | return compare(v, other) <= 0 50 | } 51 | 52 | // GreaterThan checks if a version is greater than another 53 | func GreaterThan(v, other string) bool { 54 | return compare(v, other) == 1 55 | } 56 | 57 | // GreaterThanOrEqualTo checks if a version is greater than or equal to another 58 | func GreaterThanOrEqualTo(v, other string) bool { 59 | return compare(v, other) >= 0 60 | } 61 | 62 | // Equal checks if a version is equal to another 63 | func Equal(v, other string) bool { 64 | return compare(v, other) == 0 65 | } 66 | -------------------------------------------------------------------------------- /docker/types/versions/compare_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package versions // import "github.com/ory/dockertest/v3/docker/types/versions" 5 | 6 | import ( 7 | "testing" 8 | ) 9 | 10 | func assertVersion(t *testing.T, a, b string, result int) { 11 | if r := compare(a, b); r != result { 12 | t.Fatalf("Unexpected version comparison result. Found %d, expected %d", r, result) 13 | } 14 | } 15 | 16 | func TestCompareVersion(t *testing.T) { 17 | assertVersion(t, "1.12", "1.12", 0) 18 | assertVersion(t, "1.0.0", "1", 0) 19 | assertVersion(t, "1", "1.0.0", 0) 20 | assertVersion(t, "1.05.00.0156", "1.0.221.9289", 1) 21 | assertVersion(t, "1", "1.0.1", -1) 22 | assertVersion(t, "1.0.1", "1", 1) 23 | assertVersion(t, "1.0.1", "1.0.2", -1) 24 | assertVersion(t, "1.0.2", "1.0.3", -1) 25 | assertVersion(t, "1.0.3", "1.1", -1) 26 | assertVersion(t, "1.1", "1.1.1", -1) 27 | assertVersion(t, "1.1.1", "1.1.2", -1) 28 | assertVersion(t, "1.1.2", "1.2", -1) 29 | } 30 | -------------------------------------------------------------------------------- /docker/types/versions/v1p19/types.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package v1p19 provides specific API types for the API version 1, patch 19. 5 | package v1p19 // import "github.com/ory/dockertest/v3/docker/types/versions/v1p19" 6 | 7 | import ( 8 | "github.com/docker/go-connections/nat" 9 | "github.com/ory/dockertest/v3/docker/types" 10 | "github.com/ory/dockertest/v3/docker/types/container" 11 | "github.com/ory/dockertest/v3/docker/types/versions/v1p20" 12 | ) 13 | 14 | // ContainerJSON is a backcompatibility struct for APIs prior to 1.20. 15 | // Note this is not used by the Windows daemon. 16 | type ContainerJSON struct { 17 | *types.ContainerJSONBase 18 | Volumes map[string]string 19 | VolumesRW map[string]bool 20 | Config *ContainerConfig 21 | NetworkSettings *v1p20.NetworkSettings 22 | } 23 | 24 | // ContainerConfig is a backcompatibility struct for APIs prior to 1.20. 25 | type ContainerConfig struct { 26 | *container.Config 27 | 28 | MacAddress string 29 | NetworkDisabled bool 30 | ExposedPorts map[nat.Port]struct{} 31 | 32 | // backward compatibility, they now live in HostConfig 33 | VolumeDriver string 34 | Memory int64 35 | MemorySwap int64 36 | CPUShares int64 `json:"CpuShares"` 37 | CPUSet string `json:"Cpuset"` 38 | } 39 | -------------------------------------------------------------------------------- /docker/types/versions/v1p20/types.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package v1p20 provides specific API types for the API version 1, patch 20. 5 | package v1p20 // import "github.com/ory/dockertest/v3/docker/types/versions/v1p20" 6 | 7 | import ( 8 | "github.com/docker/go-connections/nat" 9 | "github.com/ory/dockertest/v3/docker/types" 10 | "github.com/ory/dockertest/v3/docker/types/container" 11 | ) 12 | 13 | // ContainerJSON is a backcompatibility struct for the API 1.20 14 | type ContainerJSON struct { 15 | *types.ContainerJSONBase 16 | Mounts []types.MountPoint 17 | Config *ContainerConfig 18 | NetworkSettings *NetworkSettings 19 | } 20 | 21 | // ContainerConfig is a backcompatibility struct used in ContainerJSON for the API 1.20 22 | type ContainerConfig struct { 23 | *container.Config 24 | 25 | MacAddress string 26 | NetworkDisabled bool 27 | ExposedPorts map[nat.Port]struct{} 28 | 29 | // backward compatibility, they now live in HostConfig 30 | VolumeDriver string 31 | } 32 | 33 | // StatsJSON is a backcompatibility struct used in Stats for APIs prior to 1.21 34 | type StatsJSON struct { 35 | types.Stats 36 | Network types.NetworkStats `json:"network,omitempty"` 37 | } 38 | 39 | // NetworkSettings is a backward compatible struct for APIs prior to 1.21 40 | type NetworkSettings struct { 41 | types.NetworkSettingsBase 42 | types.DefaultNetworkSettings 43 | } 44 | -------------------------------------------------------------------------------- /docker/types/volume.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2024 Ory Corp 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package types 5 | 6 | // This file was generated by the swagger tool. 7 | // Editing this file might prove futile when you re-run the swagger generate command 8 | 9 | // Volume volume 10 | // swagger:model Volume 11 | type Volume struct { 12 | 13 | // Date/Time the volume was created. 14 | CreatedAt string `json:"CreatedAt,omitempty"` 15 | 16 | // Name of the volume driver used by the volume. 17 | // Required: true 18 | Driver string `json:"Driver"` 19 | 20 | // User-defined key/value metadata. 21 | // Required: true 22 | Labels map[string]string `json:"Labels"` 23 | 24 | // Mount path of the volume on the host. 25 | // Required: true 26 | Mountpoint string `json:"Mountpoint"` 27 | 28 | // Name of the volume. 29 | // Required: true 30 | Name string `json:"Name"` 31 | 32 | // The driver specific options used when creating the volume. 33 | // Required: true 34 | Options map[string]string `json:"Options"` 35 | 36 | // The level at which the volume exists. Either `global` for cluster-wide, or `local` for machine level. 37 | // Required: true 38 | Scope string `json:"Scope"` 39 | 40 | // Low-level details about the volume, provided by the volume driver. 41 | // Details are returned as a map with key/value pairs: 42 | // `{"key":"value","key2":"value2"}`. 43 | // 44 | // The `Status` field is optional, and is omitted if the volume driver 45 | // does not support this feature. 46 | // 47 | Status map[string]interface{} `json:"Status,omitempty"` 48 | 49 | // usage data 50 | UsageData *VolumeUsageData `json:"UsageData,omitempty"` 51 | } 52 | 53 | // VolumeUsageData Usage details about the volume. This information is used by the 54 | // `GET /system/df` endpoint, and omitted in other endpoints. 55 | // 56 | // swagger:model VolumeUsageData 57 | type VolumeUsageData struct { 58 | 59 | // The number of containers referencing this volume. This field 60 | // is set to `-1` if the reference-count is not available. 61 | // 62 | // Required: true 63 | RefCount int64 `json:"RefCount"` 64 | 65 | // Amount of disk space used by the volume (in bytes). This information 66 | // is only available for volumes created with the `"local"` volume 67 | // driver. For volumes created with other volume drivers, this field 68 | // is set to `-1` ("not available") 69 | // 70 | // Required: true 71 | Size int64 `json:"Size"` 72 | } 73 | -------------------------------------------------------------------------------- /docs/images/banner_dockertest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ory/dockertest/8c686a03019f80bbc4dcd2548951b92ff64f12df/docs/images/banner_dockertest.png -------------------------------------------------------------------------------- /examples/BuildDockerfile.md: -------------------------------------------------------------------------------- 1 | `./db/image/Dockerfile` 2 | 3 | ```Dockerfile 4 | FROM postgres:latest 5 | 6 | # Add your customizations here 7 | ``` 8 | 9 | `./db_test.go` 10 | 11 | ```go 12 | pool, err := dockertest.NewPool("") 13 | if err != nil { 14 | log.Fatalf("Could not construct pool: %s", err) 15 | } 16 | 17 | err = pool.Client.Ping() 18 | if err != nil { 19 | log.Fatalf("Could not connect to Docker: %s", err) 20 | } 21 | 22 | // Build and run the given Dockerfile 23 | resource, err := pool.BuildAndRun("my-postgres-test-image", "./db/image/Dockerfile", []string{}) 24 | if err != nil { 25 | log.Fatalf("Could not start resource: %s", err) 26 | } 27 | 28 | if err = pool.Retry(func() error { 29 | var err error 30 | db, err = sql.Open("postgres", fmt.Sprintf("postgres://postgres:secret@localhost:%s/%s?sslmode=disable", resource.GetPort("5432/tcp"), database)) 31 | if err != nil { 32 | return err 33 | } 34 | return db.Ping() 35 | }); err != nil { 36 | log.Fatalf("Could not connect to docker: %s", err) 37 | } 38 | 39 | // When you're done, kill and remove the container 40 | if err = pool.Purge(resource); err != nil { 41 | log.Fatalf("Could not purge resource: %s", err) 42 | } 43 | ``` 44 | -------------------------------------------------------------------------------- /examples/Cassandra.md: -------------------------------------------------------------------------------- 1 | ```go 2 | var db *mgo.Session 3 | var err error 4 | 5 | pool, err := dockertest.NewPool("") 6 | if err != nil { 7 | log.Fatalf("Could not construct pool: %s", err) 8 | } 9 | 10 | err = pool.Client.Ping() 11 | if err != nil { 12 | log.Fatalf("Could not connect to Docker: %s", err) 13 | } 14 | 15 | options := &dockertest.RunOptions{ 16 | Repository: "cassandra", 17 | Tag: "latest", 18 | Mounts: []string{"/tmp/local-cassandra:/etc/cassandra"}, 19 | } 20 | 21 | resource, err := pool.RunWithOptions(options) 22 | if err != nil { 23 | log.Fatalf("Could not start resource: %s", err) 24 | } 25 | 26 | retURL = fmt.Sprintf("localhost:%s", resource.GetPort("9042/tcp")) 27 | port, _ := strconv.Atoi(resource.GetPort("9042/tcp")) 28 | 29 | // exponential backoff-retry, because the application in the container might not be ready to accept connections yet 30 | if err := pool.Retry(func() error { 31 | clusterConfig := gocql.NewCluster(retURL) 32 | clusterConfig.Authenticator = gocql.PasswordAuthenticator{ 33 | Username: "cassandra", 34 | Password: "cassandra", 35 | } 36 | clusterConfig.ProtoVersion = 4 37 | clusterConfig.Port = port 38 | log.Printf("%v", clusterConfig.Port) 39 | 40 | session, err := clusterConfig.CreateSession() 41 | if err != nil { 42 | return fmt.Errorf("error creating session: %s", err) 43 | } 44 | defer session.Close() 45 | return nil 46 | }); err != nil { 47 | log.Fatalf("Could not connect to docker: %s", err) 48 | } 49 | 50 | // When you're done, kill and remove the container 51 | if err = pool.Purge(resource); err != nil { 52 | log.Fatalf("Could not purge resource: %s", err) 53 | } 54 | ``` 55 | -------------------------------------------------------------------------------- /examples/CockroachDB.md: -------------------------------------------------------------------------------- 1 | ```go 2 | var db *sql.DB 3 | var err error 4 | pool, err := dockertest.NewPool("") 5 | if err != nil { 6 | log.Fatalf("Could not construct pool: %s", err) 7 | } 8 | 9 | err = pool.Client.Ping() 10 | if err != nil { 11 | log.Fatalf("Could not connect to Docker: %s", err) 12 | } 13 | 14 | resource, err := pool.RunWithOptions(&dockertest.RunOptions{Repository: "cockroachdb/cockroach", Tag: "v19.2.4", Cmd: []string{"start-single-node", "--insecure"}}) 15 | if err != nil { 16 | log.Fatalf("Could not start resource: %s", err) 17 | } 18 | 19 | if err = pool.Retry(func() error { 20 | var err error 21 | db, err = sql.Open("postgres", fmt.Sprintf("postgresql://root@localhost:%s/defaultdb?sslmode=disable", resource.GetPort("26257/tcp"))) 22 | if err != nil { 23 | return err 24 | } 25 | return db.Ping() 26 | }); err != nil { 27 | log.Fatalf("Could not connect to cockroach container: %s", err) 28 | } 29 | 30 | // When you're done, kill and remove the container 31 | if err = pool.Purge(resource); err != nil { 32 | log.Fatalf("Could not purge resource: %s", err) 33 | } 34 | ``` 35 | -------------------------------------------------------------------------------- /examples/Minio.md: -------------------------------------------------------------------------------- 1 | ```go 2 | var minioClient *minio.Client 3 | var err error 4 | 5 | pool, err := dockertest.NewPool("") 6 | if err != nil { 7 | log.Fatalf("Could not construct pool: %s", err) 8 | } 9 | 10 | err = pool.Client.Ping() 11 | if err != nil { 12 | log.Fatalf("Could not connect to Docker: %s", err) 13 | } 14 | 15 | options := &dockertest.RunOptions{ 16 | Repository: "minio/minio", 17 | Tag: "latest", 18 | Cmd: []string{"server", "/data"}, 19 | PortBindings: map[dc.Port][]dc.PortBinding{ 20 | "9000/tcp": []dc.PortBinding{{HostPort: "9000"}}, 21 | }, 22 | Env: []string{"MINIO_ACCESS_KEY=MYACCESSKEY", "MINIO_SECRET_KEY=MYSECRETKEY"}, 23 | } 24 | 25 | resource, err := pool.RunWithOptions(options) 26 | if err != nil { 27 | log.Fatalf("Could not start resource: %s", err) 28 | } 29 | 30 | endpoint := fmt.Sprintf("localhost:%s", resource.GetPort("9000/tcp")) 31 | // or you could use the following, because we mapped the port 9000 to the port 9000 on the host 32 | // endpoint := "localhost:9000" 33 | 34 | // exponential backoff-retry, because the application in the container might not be ready to accept connections yet 35 | // the minio client does not do service discovery for you (i.e. it does not check if connection can be established), so we have to use the health check 36 | if err := pool.Retry(func() error { 37 | url := fmt.Sprintf("http://%s/minio/health/live", endpoint) 38 | resp, err := http.Get(url) 39 | if err != nil { 40 | return err 41 | } 42 | defer resp.Body.Close() 43 | if resp.StatusCode != http.StatusOK { 44 | return fmt.Errorf("status code not OK") 45 | } 46 | return nil 47 | }); err != nil { 48 | log.Fatalf("Could not connect to docker: %s", err) 49 | } 50 | 51 | // now we can instantiate minio client 52 | minioClient, err := minio.New(endpoint, &minio.Options{ 53 | Creds: credentials.NewStaticV4("MYACCESSKEY", "MYSECRETKEY", ""), 54 | Secure: false, 55 | }) 56 | if err != nil { 57 | log.Println("Failed to create minio client:", err) 58 | return err 59 | } 60 | log.Printf("%#v\n", minioClient) // minioClient is now set up 61 | 62 | // now we can use the client, for example, to list the buckets 63 | buckets, err := minioClient.ListBuckets(context.Background()) 64 | if err != nil { 65 | log.Fatalf("error while listing buckets: %v", err) 66 | } 67 | fmt.Printf("buckets: %+v", buckets) 68 | 69 | // When you're done, kill and remove the container 70 | if err = pool.Purge(resource); err != nil { 71 | log.Fatalf("Could not purge resource: %s", err) 72 | } 73 | ``` 74 | -------------------------------------------------------------------------------- /examples/MongoDB.md: -------------------------------------------------------------------------------- 1 | ```go 2 | package mongodb 3 | 4 | import ( 5 | "context" 6 | "fmt" 7 | "log" 8 | "os" 9 | "testing" 10 | 11 | "github.com/ory/dockertest/v3" 12 | "github.com/ory/dockertest/v3/docker" 13 | "go.mongodb.org/mongo-driver/mongo" 14 | "go.mongodb.org/mongo-driver/mongo/options" 15 | ) 16 | 17 | var dbClient *mongo.Client 18 | 19 | func TestMain(m *testing.M) { 20 | pool, err := dockertest.NewPool("") 21 | if err != nil { 22 | log.Fatalf("Could not construct pool: %s", err) 23 | } 24 | 25 | err = pool.Client.Ping() 26 | if err != nil { 27 | log.Fatalf("Could not connect to Docker: %s", err) 28 | } 29 | 30 | // pull mongodb docker image for version 5.0 31 | resource, err := pool.RunWithOptions(&dockertest.RunOptions{ 32 | Repository: "mongo", 33 | Tag: "5.0", 34 | Env: []string{ 35 | // username and password for mongodb superuser 36 | "MONGO_INITDB_ROOT_USERNAME=root", 37 | "MONGO_INITDB_ROOT_PASSWORD=password", 38 | }, 39 | }, func(config *docker.HostConfig) { 40 | // set AutoRemove to true so that stopped container goes away by itself 41 | config.AutoRemove = true 42 | config.RestartPolicy = docker.RestartPolicy{ 43 | Name: "no", 44 | } 45 | }) 46 | if err != nil { 47 | log.Fatalf("Could not start resource: %s", err) 48 | } 49 | 50 | // exponential backoff-retry, because the application in the container might not be ready to accept connections yet 51 | err = pool.Retry(func() error { 52 | var err error 53 | dbClient, err = mongo.Connect( 54 | context.TODO(), 55 | options.Client().ApplyURI( 56 | fmt.Sprintf("mongodb://root:password@localhost:%s", resource.GetPort("27017/tcp")), 57 | ), 58 | ) 59 | if err != nil { 60 | return err 61 | } 62 | return dbClient.Ping(context.TODO(), nil) 63 | }) 64 | 65 | if err != nil { 66 | log.Fatalf("Could not connect to docker: %s", err) 67 | } 68 | 69 | defer func() { 70 | // When you're done, kill and remove the container 71 | if err = pool.Purge(resource); err != nil { 72 | log.Fatalf("Could not purge resource: %s", err) 73 | } 74 | 75 | // disconnect mongodb client 76 | if err = dbClient.Disconnect(context.TODO()); err != nil { 77 | panic(err) 78 | } 79 | }() 80 | 81 | // run tests 82 | m.Run() 83 | } 84 | 85 | ``` 86 | -------------------------------------------------------------------------------- /examples/MultipleTestContainers.md: -------------------------------------------------------------------------------- 1 | # Creating Multiple Test Containers 2 | 3 | Follow the guide: 4 | [Creating Multiple Test Containers with ory/dockertest in Go](https://akoserwal.medium.com/creating-multiple-test-containers-with-ory-dockertest-in-go-5b8311614e7b) 5 | 6 | Code: 7 | [LocalTestContainers](https://github.com/akoserwal/multi-containers-dockertest/blob/main/LocalTestContainers.go) 8 | 9 | Author: Abhishek Koserwal [https://github.com/akoserwal] 10 | -------------------------------------------------------------------------------- /examples/MySQL.md: -------------------------------------------------------------------------------- 1 | ```go 2 | var db *sql.DB 3 | var err error 4 | pool, err := dockertest.NewPool("") 5 | pool.MaxWait = time.Minute * 2 6 | if err != nil { 7 | log.Fatalf("Could not construct pool: %s", err) 8 | } 9 | 10 | err = pool.Client.Ping() 11 | if err != nil { 12 | log.Fatalf("Could not connect to Docker: %s", err) 13 | } 14 | 15 | resource, err := pool.Run("mysql", "5.7", []string{"MYSQL_ROOT_PASSWORD=secret"}) 16 | if err != nil { 17 | log.Fatalf("Could not start resource: %s", err) 18 | } 19 | 20 | if err = pool.Retry(func() error { 21 | var err error 22 | db, err = sql.Open("mysql", fmt.Sprintf("root:secret@(localhost:%s)/mysql?parseTime=true", resource.GetPort("3306/tcp"))) 23 | if err != nil { 24 | return err 25 | } 26 | return db.Ping() 27 | }); err != nil { 28 | log.Fatalf("Could not connect to docker: %s", err) 29 | } 30 | 31 | // When you're done, kill and remove the container 32 | if err = pool.Purge(resource); err != nil { 33 | log.Fatalf("Could not purge resource: %s", err) 34 | } 35 | ``` 36 | -------------------------------------------------------------------------------- /examples/PostgreSQL.md: -------------------------------------------------------------------------------- 1 | ```go 2 | package dockertestpsql_test 3 | 4 | import ( 5 | "database/sql" 6 | "fmt" 7 | "os" 8 | "testing" 9 | "time" 10 | 11 | _ "github.com/lib/pq" 12 | "github.com/ory/dockertest/v3" 13 | "github.com/ory/dockertest/v3/docker" 14 | log "github.com/sirupsen/logrus" 15 | ) 16 | 17 | var db *sql.DB 18 | 19 | func TestMain(m *testing.M) { 20 | // uses a sensible default on windows (tcp/http) and linux/osx (socket) 21 | pool, err := dockertest.NewPool("") 22 | if err != nil { 23 | log.Fatalf("Could not construct pool: %s", err) 24 | } 25 | 26 | err = pool.Client.Ping() 27 | if err != nil { 28 | log.Fatalf("Could not connect to Docker: %s", err) 29 | } 30 | 31 | // pulls an image, creates a container based on it and runs it 32 | resource, err := pool.RunWithOptions(&dockertest.RunOptions{ 33 | Repository: "postgres", 34 | Tag: "11", 35 | Env: []string{ 36 | "POSTGRES_PASSWORD=secret", 37 | "POSTGRES_USER=user_name", 38 | "POSTGRES_DB=dbname", 39 | "listen_addresses = '*'", 40 | }, 41 | }, func(config *docker.HostConfig) { 42 | // set AutoRemove to true so that stopped container goes away by itself 43 | config.AutoRemove = true 44 | config.RestartPolicy = docker.RestartPolicy{Name: "no"} 45 | }) 46 | if err != nil { 47 | log.Fatalf("Could not start resource: %s", err) 48 | } 49 | 50 | hostAndPort := resource.GetHostPort("5432/tcp") 51 | databaseUrl := fmt.Sprintf("postgres://user_name:secret@%s/dbname?sslmode=disable", hostAndPort) 52 | 53 | log.Println("Connecting to database on url: ", databaseUrl) 54 | 55 | resource.Expire(120) // Tell docker to hard kill the container in 120 seconds 56 | 57 | // exponential backoff-retry, because the application in the container might not be ready to accept connections yet 58 | pool.MaxWait = 120 * time.Second 59 | if err = pool.Retry(func() error { 60 | db, err = sql.Open("postgres", databaseUrl) 61 | if err != nil { 62 | return err 63 | } 64 | return db.Ping() 65 | }); err != nil { 66 | log.Fatalf("Could not connect to docker: %s", err) 67 | } 68 | 69 | defer func() { 70 | if err := pool.Purge(resource); err != nil { 71 | log.Fatalf("Could not purge resource: %s", err) 72 | } 73 | }() 74 | 75 | // run tests 76 | m.Run() 77 | } 78 | 79 | func TestRealbob(t *testing.T) { 80 | // all tests 81 | } 82 | 83 | ``` 84 | -------------------------------------------------------------------------------- /examples/Redis.md: -------------------------------------------------------------------------------- 1 | ```go 2 | var db *redis.Client 3 | var err error 4 | pool, err := dockertest.NewPool("") 5 | if err != nil { 6 | log.Fatalf("Could not construct pool: %s", err) 7 | } 8 | 9 | err = pool.Client.Ping() 10 | if err != nil { 11 | log.Fatalf("Could not connect to Docker: %s", err) 12 | } 13 | 14 | resource, err := pool.Run("redis", "3.2", nil) 15 | if err != nil { 16 | log.Fatalf("Could not start resource: %s", err) 17 | } 18 | 19 | if err = pool.Retry(func() error { 20 | db = redis.NewClient(&redis.Options{ 21 | Addr: fmt.Sprintf("localhost:%s", resource.GetPort("6379/tcp")), 22 | }) 23 | 24 | return db.Ping().Err() 25 | }); err != nil { 26 | log.Fatalf("Could not connect to docker: %s", err) 27 | } 28 | 29 | // When you're done, kill and remove the container 30 | if err = pool.Purge(resource); err != nil { 31 | log.Fatalf("Could not purge resource: %s", err) 32 | } 33 | ``` 34 | -------------------------------------------------------------------------------- /examples/RethinkDB.md: -------------------------------------------------------------------------------- 1 | ```go 2 | var session *r.Session 3 | var err error 4 | pool, err := dockertest.NewPool("") 5 | if err != nil { 6 | log.Fatalf("Could not construct pool: %s", err) 7 | } 8 | 9 | err = pool.Client.Ping() 10 | if err != nil { 11 | log.Fatalf("Could not connect to Docker: %s", err) 12 | } 13 | 14 | resource, err := pool.Run("rethinkdb", "2.3", []string{""}) 15 | if err != nil { 16 | log.Fatalf("Could not start resource: %s", err) 17 | } 18 | 19 | if err = pool.Retry(func() error { 20 | if session, err = r.Connect(r.ConnectOpts{Address: fmt.Sprintf("localhost:%s", resource.GetPort("28015/tcp")), Database: database}); err != nil { 21 | return err 22 | } else if _, err = r.DBCreate(database).RunWrite(session); err != nil { 23 | log.Printf("Database exists: %s", err) 24 | return err 25 | } 26 | 27 | for _, table := range tables { 28 | if _, err = r.TableCreate(table).RunWrite(session); err != nil { 29 | log.Printf("Could not create table: %s", err) 30 | return err 31 | } 32 | } 33 | 34 | time.Sleep(100 * time.Millisecond) 35 | return nil 36 | }); err != nil { 37 | log.Fatalf("Could not connect to docker: %s", err) 38 | } 39 | 40 | // When you're done, kill and remove the container 41 | if err = pool.Purge(resource); err != nil { 42 | log.Fatalf("Could not purge resource: %s", err) 43 | } 44 | ``` 45 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ory/dockertest/v3 2 | 3 | go 1.22 4 | 5 | require ( 6 | github.com/Microsoft/go-winio v0.6.2 7 | github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 8 | github.com/cenkalti/backoff/v4 v4.3.0 9 | github.com/containerd/continuity v0.4.5 10 | github.com/docker/cli v27.4.1+incompatible 11 | github.com/docker/go-connections v0.5.0 12 | github.com/docker/go-units v0.5.0 13 | github.com/go-sql-driver/mysql v1.9.1 14 | github.com/lib/pq v1.10.9 15 | github.com/moby/term v0.5.0 16 | github.com/opencontainers/image-spec v1.1.0 17 | github.com/opencontainers/runc v1.2.6 18 | github.com/sirupsen/logrus v1.9.3 19 | github.com/stretchr/testify v1.10.0 20 | golang.org/x/sys v0.28.0 21 | ) 22 | 23 | require ( 24 | dario.cat/mergo v1.0.0 // indirect 25 | github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect 26 | github.com/davecgh/go-spew v1.1.1 // indirect 27 | github.com/docker/docker v27.1.1+incompatible // indirect 28 | ) 29 | 30 | require ( 31 | filippo.io/edwards25519 v1.1.0 // indirect 32 | github.com/go-viper/mapstructure/v2 v2.1.0 // indirect 33 | github.com/gogo/protobuf v1.3.2 // indirect 34 | github.com/google/go-cmp v0.6.0 // indirect 35 | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect 36 | github.com/moby/docker-image-spec v1.3.1 // indirect 37 | github.com/moby/sys/user v0.3.0 // indirect 38 | github.com/opencontainers/go-digest v1.0.0 // indirect 39 | github.com/pkg/errors v0.9.1 // indirect 40 | github.com/pmezard/go-difflib v1.0.0 // indirect 41 | github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect 42 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect 43 | github.com/xeipuuv/gojsonschema v1.2.0 // indirect 44 | gopkg.in/yaml.v2 v2.4.0 // indirect 45 | gopkg.in/yaml.v3 v3.0.1 // indirect 46 | gotest.tools/v3 v3.5.1 // indirect 47 | ) 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "prettier": "ory-prettier-styles", 4 | "devDependencies": { 5 | "license-checker": "^25.0.1", 6 | "ory-prettier-styles": "1.3.0", 7 | "prettier": "2.7.1" 8 | } 9 | } 10 | --------------------------------------------------------------------------------