diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fbe5f9c..690293f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @pinglin @phelan164 @xiaofei-du +* @TobiaszCudnik @heiruwu @pinglin diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md deleted file mode 100644 index 5f4a38d..0000000 --- a/.github/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,133 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, caste, color, religion, or sexual -identity and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the overall - community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or advances of - any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email address, - without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, -posting via an official social media account, or acting as an appointed -representative at an online or offline event. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -[contact@instill.tech](contact@instill.tech). - -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series of -actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or permanent -ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within the -community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.1, available at -[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. - -Community Impact Guidelines were inspired by -[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. - -For answers to common questions about this code of conduct, see the FAQ at -[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at -[https://www.contributor-covenant.org/translations][translations]. - -[homepage]: https://www.contributor-covenant.org -[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html -[Mozilla CoC]: https://github.com/mozilla/diversity -[FAQ]: https://www.contributor-covenant.org/faq -[translations]: https://www.contributor-covenant.org/translations diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index 3f83a83..0000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1,16 +0,0 @@ -# Contributing Guidelines - -Hello! Thanks for your interest in contributing to the codebase. - -## How to contribute - -TBD - - -## Submitting a pull request - -To make an efficient review process, we very much appreciate if the PR commits - -- follow the [conventional commits guidelines](https://www.conventionalcommits.org/), -- follow the [7 rules of commit messages](https://chris.beams.io/posts/git-commit/), and -- are rearranged to squash trivial commits together (use [git rebase](http://gitready.com/advanced/2009/03/20/reorder-commits-with-rebase.html)). diff --git a/.github/LICENSE b/.github/LICENSE new file mode 100644 index 0000000..3221cab --- /dev/null +++ b/.github/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2023 Instill AI + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index c4c64b3..0000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,7 +0,0 @@ -Because - -- (write the reason why we need to consider this PR in a list) - -This commit - -- (write the summary of all commits in this PR in a list) diff --git a/.github/SECURITY.md b/.github/SECURITY.md deleted file mode 100644 index 1b00e93..0000000 --- a/.github/SECURITY.md +++ /dev/null @@ -1,3 +0,0 @@ -If you discover a security issue in this repository, please contact us through security@instill.tech. - -Thanks for helping make Instill CLI safe for everyone. diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..14f8ed7 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,2 @@ +base: + - "**" diff --git a/.github/semantic.yml b/.github/semantic.yml deleted file mode 100644 index 96f9233..0000000 --- a/.github/semantic.yml +++ /dev/null @@ -1,2 +0,0 @@ -# Always validate the PR title AND all the commits -titleAndCommits: true diff --git a/.github/workflows/add-issue-to-prj.yml b/.github/workflows/add-issue-to-prj.yml deleted file mode 100644 index 9f5cb97..0000000 --- a/.github/workflows/add-issue-to-prj.yml +++ /dev/null @@ -1,91 +0,0 @@ -name: Add Issue to Project - -on: - issues: - types: - - opened - -jobs: - track_issue: - runs-on: ubuntu-latest - steps: - - name: Get project data - env: - GITHUB_TOKEN: ${{ secrets.botGitHubToken }} - ORGANIZATION: instill-ai - PROJECT_NUMBER: 5 # Versatile Data Pipeline (VDP) project - run: | - gh api graphql -f query=' - query($org: String!, $number: Int!) { - organization(login: $org){ - projectNext(number: $number) { - id - fields(first:20) { - nodes { - id - name - settings - } - } - } - } - }' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json - - echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV - echo 'DATE_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Date posted") | .id' project_data.json) >> $GITHUB_ENV - echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV - echo 'TODO_OPTION_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") |.settings | fromjson.options[] | select(.name=="Todo") |.id' project_data.json) >> $GITHUB_ENV - - - name: Add Issue to project - env: - GITHUB_TOKEN: ${{ secrets.botGitHubToken }} - ISSUE_ID: ${{ github.event.issue.node_id }} - run: | - item_id="$( gh api graphql -f query=' - mutation($project:ID!, $issue:ID!) { - addProjectNextItem(input: {projectId: $project, contentId: $issue}) { - projectNextItem { - id - } - } - }' -f project=$PROJECT_ID -f issue=$ISSUE_ID --jq '.data.addProjectNextItem.projectNextItem.id')" - - echo 'ITEM_ID='$item_id >> $GITHUB_ENV - - - name: Get date - run: echo "DATE=$(date +"%Y-%m-%d")" >> $GITHUB_ENV - - - name: Set fields - env: - GITHUB_TOKEN: ${{ secrets.botGitHubToken }} - run: | - gh api graphql -f query=' - mutation ( - $project: ID! - $item: ID! - $status_field: ID! - $status_value: String! - $date_field: ID! - $date_value: String! - ) { - set_status: updateProjectNextItemField(input: { - projectId: $project - itemId: $item - fieldId: $status_field - value: $status_value - }) { - projectNextItem { - id - } - } - set_date_posted: updateProjectNextItemField(input: { - projectId: $project - itemId: $item - fieldId: $date_field - value: $date_value - }) { - projectNextItem { - id - } - } - }' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.TODO_OPTION_ID }} -f date_field=$DATE_FIELD_ID -f date_value=$DATE --silent diff --git a/.github/workflows/add-label-to-pr.yml b/.github/workflows/add-label-to-pr.yml new file mode 100644 index 0000000..3fa2d15 --- /dev/null +++ b/.github/workflows/add-label-to-pr.yml @@ -0,0 +1,13 @@ +name: Add PR to Project + +on: + pull_request_target: + types: + - opened + - synchronize + +jobs: + triage: + uses: instill-ai/.github/.github/workflows/add-label-to-pr.yml@main + secrets: + botGitHubToken: ${{ secrets.botGitHubToken }} diff --git a/.github/workflows/add-pr-to-prj.yml b/.github/workflows/add-pr-to-prj.yml index 606ce3b..ff338ef 100644 --- a/.github/workflows/add-pr-to-prj.yml +++ b/.github/workflows/add-pr-to-prj.yml @@ -1,92 +1,14 @@ name: Add PR to Project on: - pull_request: + pull_request_target: types: - opened - - ready_for_review + jobs: track_pr: - runs-on: ubuntu-latest - if: ${{ !github.event.pull_request.draft }} - steps: - - name: Get project data - env: - GITHUB_TOKEN: ${{ secrets.botGitHubToken }} - ORGANIZATION: instill-ai - PROJECT_NUMBER: 5 # Versatile Data Pipeline (VDP) project - run: | - gh api graphql -f query=' - query($org: String!, $number: Int!) { - organization(login: $org){ - projectNext(number: $number) { - id - fields(first:20) { - nodes { - id - name - settings - } - } - } - } - }' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json - - echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV - echo 'DATE_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Date posted") | .id' project_data.json) >> $GITHUB_ENV - echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV - echo 'TODO_OPTION_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") |.settings | fromjson.options[] | select(.name=="Todo") |.id' project_data.json) >> $GITHUB_ENV - - - name: Add PR to project - env: - GITHUB_TOKEN: ${{ secrets.botGitHubToken }} - PR_ID: ${{ github.event.pull_request.node_id }} - run: | - item_id="$( gh api graphql -f query=' - mutation($project:ID!, $pr:ID!) { - addProjectNextItem(input: {projectId: $project, contentId: $pr}) { - projectNextItem { - id - } - } - }' -f project=$PROJECT_ID -f pr=$PR_ID --jq '.data.addProjectNextItem.projectNextItem.id')" - - echo 'ITEM_ID='$item_id >> $GITHUB_ENV - - - name: Get date - run: echo "DATE=$(date +"%Y-%m-%d")" >> $GITHUB_ENV - - - name: Set fields - env: - GITHUB_TOKEN: ${{ secrets.botGitHubToken }} - run: | - gh api graphql -f query=' - mutation ( - $project: ID! - $item: ID! - $status_field: ID! - $status_value: String! - $date_field: ID! - $date_value: String! - ) { - set_status: updateProjectNextItemField(input: { - projectId: $project - itemId: $item - fieldId: $status_field - value: $status_value - }) { - projectNextItem { - id - } - } - set_date_posted: updateProjectNextItemField(input: { - projectId: $project - itemId: $item - fieldId: $date_field - value: $date_value - }) { - projectNextItem { - id - } - } - }' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.TODO_OPTION_ID }} -f date_field=$DATE_FIELD_ID -f date_value=$DATE --silent + uses: instill-ai/.github/.github/workflows/add-to-prj.yml@main + with: + project_number: 5 + secrets: + botGitHubToken: ${{ secrets.botGitHubToken }} diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 5d8520f..4160fb5 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -3,15 +3,13 @@ name: Coverage on: [push, pull_request] jobs: - codecov: name: codecov runs-on: ubuntu-latest steps: - - - uses: actions/setup-go@v3 + - uses: actions/setup-go@v4 with: - go-version: 1.17 + go-version: "1.20" - uses: actions/checkout@v3 diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 7233b45..639075d 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -10,10 +10,10 @@ jobs: runs-on: ${{ matrix.os }} steps: - - name: Set up Go 1.17 - uses: actions/setup-go@v3 + - name: Set up Go 1.20 + uses: actions/setup-go@v4 with: - go-version: 1.17 + go-version: "1.20" - name: Check out code uses: actions/checkout@v3 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index fbd2a91..0c40a55 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,4 +1,4 @@ -name: Lint +name: Lint Codebase on: push: paths: @@ -16,10 +16,10 @@ jobs: runs-on: ubuntu-latest steps: - - name: Set up Go 1.17 - uses: actions/setup-go@v3 + - name: Set up Go 1.20 + uses: actions/setup-go@v4 with: - go-version: 1.17 + go-version: "1.20" - name: Check out code uses: actions/checkout@v3 @@ -29,7 +29,7 @@ jobs: go mod verify go mod download - LINT_VERSION=1.39.0 + LINT_VERSION=1.54.2 curl -fsSL https://github.com/golangci/golangci-lint/releases/download/v${LINT_VERSION}/golangci-lint-${LINT_VERSION}-linux-amd64.tar.gz | \ tar xz --strip-components 1 --wildcards \*/golangci-lint mkdir -p bin && mv golangci-lint bin/ diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 51e68de..c6a6250 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -1,4 +1,4 @@ -name: GoReleaser +name: Go Releaser on: push: @@ -14,10 +14,10 @@ jobs: with: fetch-depth: 0 - - name: Set up Go 1.17 - uses: actions/setup-go@v3 + - name: Set up Go 1.20 + uses: actions/setup-go@v4 with: - go-version: 1.17 + go-version: "1.20" - name: Run GoReleaser uses: goreleaser/goreleaser-action@v4 @@ -25,7 +25,15 @@ jobs: version: latest args: release --rm-dist env: + # release GITHUB_TOKEN: ${{ secrets.botGitHubToken }} - GORELEASER_CURRENT_TAG: ${{steps.changelog.outputs.tag-name}} + GORELEASER_CURRENT_TAG: ${{ steps.changelog.outputs.tag-name }} + # secrets INSTILL_OAUTH_CLIENT_ID: ${{ secrets.oauth2ClientId }} INSTILL_OAUTH_CLIENT_SECRET: ${{ secrets.oauth2ClientSecret }} + # config + INSTILL_OAUTH_ISSUER: ${{ vars.oauth2Issuer }} + INSTILL_OAUTH_HOSTNAME: ${{ vars.oauth2Hostname }} + INSTILL_OAUTH_AUDIENCE: ${{ vars.oauth2Audience }} + INSTILL_OAUTH_CALLBACK_HOST: ${{ vars.oauth2CallbackHost }} + INSTILL_OAUTH_CALLBACK_PORT: ${{ vars.oauth2CallbackPort }} diff --git a/.github/workflows/semantic.yml b/.github/workflows/semantic.yml new file mode 100644 index 0000000..9e330e5 --- /dev/null +++ b/.github/workflows/semantic.yml @@ -0,0 +1,17 @@ +name: Lint PR + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + +jobs: + main: + name: Validate PR title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v4 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.goreleaser.yml b/.goreleaser.yml index d940eab..74ecc40 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -21,8 +21,13 @@ builds: - -s -w - -X github.com/instill-ai/cli/internal/build.Version={{ .Version }} - -X github.com/instill-ai/cli/internal/build.Date={{ time "2006-01-02" }} - - -X github.com/instill-ai/cli/internal/oauth2.oauthClientID={{ .Env.INSTILL_OAUTH_CLIENT_ID }} - - -X github.com/instill-ai/cli/internal/oauth2.oauthClientSecret={{ .Env.INSTILL_OAUTH_CLIENT_SECRET }} + - -X github.com/instill-ai/cli/internal/oauth2.clientID={{ .Env.INSTILL_OAUTH_CLIENT_ID }} + - -X github.com/instill-ai/cli/internal/oauth2.clientSecret={{ .Env.INSTILL_OAUTH_CLIENT_SECRET }} + - -X github.com/instill-ai/cli/internal/oauth2.issuer={{ .Env.INSTILL_OAUTH_ISSUER }} + - -X github.com/instill-ai/cli/internal/oauth2.hostname={{ .Env.INSTILL_OAUTH_HOSTNAME }} + - -X github.com/instill-ai/cli/internal/oauth2.audience={{ .Env.INSTILL_OAUTH_AUDIENCE }} + - -X github.com/instill-ai/cli/internal/oauth2.callbackHost={{ .Env.INSTILL_OAUTH_CALLBACK_HOST }} + - -X github.com/instill-ai/cli/internal/oauth2.callbackPort={{ .Env.INSTILL_OAUTH_CALLBACK_PORT }} - -X main.updaterEnabled=instill-ai/cli id: macos goos: [darwin] diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 21988c3..0000000 --- a/LICENSE +++ /dev/null @@ -1,228 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2021 Instill AI Ltd. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -=============================================================================== - -MIT License - -Copyright (c) 2019 GitHub Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -=============================================================================== diff --git a/api/cache.go b/api/cache.go index 0f915c0..3648074 100644 --- a/api/cache.go +++ b/api/cache.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net/http" "os" "path/filepath" @@ -69,7 +68,7 @@ func CacheResponse(ttl time.Duration, dir string) ClientOption { func copyStream(r io.ReadCloser) (io.ReadCloser, io.ReadCloser) { b := &bytes.Buffer{} nr := io.TeeReader(r, b) - return ioutil.NopCloser(b), &readCloser{ + return io.NopCloser(b), &readCloser{ Reader: nr, Closer: r, } diff --git a/api/cache_test.go b/api/cache_test.go index a0591c9..2ba48f9 100644 --- a/api/cache_test.go +++ b/api/cache_test.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "net/http" "path/filepath" "testing" @@ -26,7 +25,7 @@ func Test_CacheResponse(t *testing.T) { } return &http.Response{ StatusCode: status, - Body: ioutil.NopCloser(bytes.NewBufferString(body)), + Body: io.NopCloser(bytes.NewBufferString(body)), }, nil }, } @@ -44,7 +43,7 @@ func Test_CacheResponse(t *testing.T) { return "", err } defer res.Body.Close() - resBody, err := ioutil.ReadAll(res.Body) + resBody, err := io.ReadAll(res.Body) if err != nil { err = fmt.Errorf("ReadAll: %w", err) } diff --git a/api/client.go b/api/client.go index fc1c243..eb65ee6 100644 --- a/api/client.go +++ b/api/client.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "net/url" "regexp" @@ -162,7 +161,7 @@ func (c Client) REST(hostname string, method string, p string, body io.Reader, d return nil } - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { return err } @@ -192,7 +191,7 @@ func HandleHTTPError(resp *http.Response) error { return httpError } - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { httpError.Message = err.Error() return httpError diff --git a/cmd/instill/main.go b/cmd/instill/main.go index 69353a0..54f5b42 100644 --- a/cmd/instill/main.go +++ b/cmd/instill/main.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "io" + "log" "net" "os" "os/exec" @@ -16,6 +17,7 @@ import ( "github.com/cli/safeexec" "github.com/mattn/go-colorable" + "github.com/dotenv-org/godotenvvault" "github.com/mgutz/ansi" "github.com/spf13/cobra" @@ -46,6 +48,13 @@ func main() { } func mainRun() exitCode { + // load .env in dev mode + if build.Version == "" { + err := godotenvvault.Load() + if err != nil { + log.Fatal("Error loading .env file") + } + } buildDate := build.Date buildVersion := build.Version diff --git a/go.mod b/go.mod index 21d9fee..695ae75 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/instill-ai/cli -go 1.17 +go 1.20 require ( github.com/AlecAivazis/survey/v2 v2.3.2 @@ -9,7 +9,9 @@ require ( github.com/charmbracelet/glamour v0.3.0 github.com/cli/browser v1.1.0 github.com/cli/safeexec v1.0.0 + github.com/coreos/go-oidc/v3 v3.6.0 github.com/creack/pty v1.1.18 + github.com/dotenv-org/godotenvvault v0.6.0 github.com/google/go-cmp v0.5.9 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/hashicorp/go-version v1.3.0 @@ -27,9 +29,9 @@ require ( github.com/spf13/cobra v1.4.0 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.7.1 - golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 - golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 + golang.org/x/oauth2 v0.6.0 + golang.org/x/sys v0.6.0 + golang.org/x/term v0.6.0 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b ) @@ -40,6 +42,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dlclark/regexp2 v1.2.0 // indirect github.com/fatih/color v1.13.0 // indirect + github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/go-logr/logr v1.2.1 // indirect github.com/go-logr/stdr v1.2.0 // indirect github.com/gobuffalo/pop/v6 v6.0.1 // indirect @@ -48,6 +51,7 @@ require ( github.com/gorilla/css v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/itchyny/timefmt-go v0.1.3 // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect github.com/microcosm-cc/bluemonday v1.0.16 // indirect @@ -62,10 +66,11 @@ require ( go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.25.0 // indirect go.opentelemetry.io/otel v1.3.0 // indirect go.opentelemetry.io/otel/trace v1.3.0 // indirect - golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect + golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect + golang.org/x/net v0.8.0 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/text v0.8.0 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.27.1 // indirect + google.golang.org/protobuf v1.28.0 // indirect ) diff --git a/go.sum b/go.sum index 0e02bb3..dc3df82 100644 --- a/go.sum +++ b/go.sum @@ -281,6 +281,8 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-oidc/v3 v3.6.0 h1:AKVxfYw1Gmkn/w96z0DbT/B/xFnzTd3MkZvWLjF4n/o= +github.com/coreos/go-oidc/v3 v3.6.0/go.mod h1:ZpHUsHBucTUj6WOkrP4E20UPynbLZzhTQ1XKCXkxyPc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -340,6 +342,8 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dotenv-org/godotenvvault v0.6.0 h1:e6rUPELZaPmf6SgxxdB3nACG9VQAE8+omrSSZm0QUgk= +github.com/dotenv-org/godotenvvault v0.6.0/go.mod h1:q/635WfmO04uUBVwrDWchRPOvPWaplWC6Udm+illcS4= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -396,6 +400,8 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= +github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -789,6 +795,8 @@ github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXL github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -1389,8 +1397,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1447,8 +1455,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1463,8 +1471,8 @@ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1581,13 +1589,15 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1597,8 +1607,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1674,8 +1685,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1815,8 +1826,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/DataDog/dd-trace-go.v1 v1.33.0/go.mod h1:MFdmxQL1OfAGjPrYPU02P82Z5lJ/19f4JVAvXwK1brY= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= diff --git a/internal/config/config_file.go b/internal/config/config_file.go index 81ced77..0d53765 100644 --- a/internal/config/config_file.go +++ b/internal/config/config_file.go @@ -3,7 +3,7 @@ package config import ( "errors" "fmt" - "io/ioutil" + "io" "os" "path/filepath" "runtime" @@ -172,7 +172,7 @@ var ReadConfigFile = func(filename string) ([]byte, error) { } defer f.Close() - data, err := ioutil.ReadAll(f) + data, err := io.ReadAll(f) if err != nil { return nil, err } diff --git a/internal/config/config_file_test.go b/internal/config/config_file_test.go index 3d54745..09cc71e 100644 --- a/internal/config/config_file_test.go +++ b/internal/config/config_file_test.go @@ -3,7 +3,6 @@ package config import ( "bytes" "fmt" - "io/ioutil" "os" "path/filepath" "runtime" @@ -262,13 +261,13 @@ func Test_configFile_Write_toDisk(t *testing.T) { } expectedConfig := "pager: less\n" - if configBytes, err := ioutil.ReadFile(filepath.Join(configDir, "config.yml")); err != nil { + if configBytes, err := os.ReadFile(filepath.Join(configDir, "config.yml")); err != nil { t.Error(err) } else if string(configBytes) != expectedConfig { t.Errorf("expected config.yml %q, got %q", expectedConfig, string(configBytes)) } - if configBytes, err := ioutil.ReadFile(filepath.Join(configDir, "hosts.yml")); err != nil { + if configBytes, err := os.ReadFile(filepath.Join(configDir, "hosts.yml")); err != nil { t.Error(err) } else if string(configBytes) != "" { t.Errorf("unexpected hosts.yml: %q", string(configBytes)) @@ -290,7 +289,7 @@ func Test_autoMigrateConfigDir_noMigration_notExist(t *testing.T) { err := autoMigrateConfigDir(migrateDir) assert.Equal(t, errNotExist, err) - files, err := ioutil.ReadDir(migrateDir) + files, err := os.ReadDir(migrateDir) assert.NoError(t, err) assert.Equal(t, 0, len(files)) } @@ -312,7 +311,7 @@ func Test_autoMigrateConfigDir_noMigration_samePath(t *testing.T) { err = autoMigrateConfigDir(migrateDir) assert.Equal(t, errSamePath, err) - files, err := ioutil.ReadDir(migrateDir) + files, err := os.ReadDir(migrateDir) assert.NoError(t, err) assert.Equal(t, 0, len(files)) } @@ -333,17 +332,17 @@ func Test_autoMigrateConfigDir_migration(t *testing.T) { err := os.MkdirAll(homeConfigDir, 0755) assert.NoError(t, err) - f, err := ioutil.TempFile(homeConfigDir, "") + f, err := os.CreateTemp(homeConfigDir, "") assert.NoError(t, err) f.Close() err = autoMigrateConfigDir(migrateConfigDir) assert.NoError(t, err) - _, err = ioutil.ReadDir(homeConfigDir) + _, err = os.ReadDir(homeConfigDir) assert.True(t, os.IsNotExist(err)) - files, err := ioutil.ReadDir(migrateConfigDir) + files, err := os.ReadDir(migrateConfigDir) assert.NoError(t, err) assert.Equal(t, 1, len(files)) } @@ -432,7 +431,7 @@ func Test_autoMigrateStateDir_noMigration_notExist(t *testing.T) { err := autoMigrateStateDir(migrateDir) assert.Equal(t, errNotExist, err) - files, err := ioutil.ReadDir(migrateDir) + files, err := os.ReadDir(migrateDir) assert.NoError(t, err) assert.Equal(t, 0, len(files)) } @@ -454,7 +453,7 @@ func Test_autoMigrateStateDir_noMigration_samePath(t *testing.T) { err = autoMigrateStateDir(migrateDir) assert.Equal(t, errSamePath, err) - files, err := ioutil.ReadDir(migrateDir) + files, err := os.ReadDir(migrateDir) assert.NoError(t, err) assert.Equal(t, 0, len(files)) } @@ -475,17 +474,17 @@ func Test_autoMigrateStateDir_migration(t *testing.T) { err := os.MkdirAll(homeConfigDir, 0755) assert.NoError(t, err) - err = ioutil.WriteFile(filepath.Join(homeConfigDir, "state.yml"), nil, 0755) + err = os.WriteFile(filepath.Join(homeConfigDir, "state.yml"), nil, 0755) assert.NoError(t, err) err = autoMigrateStateDir(migrateStateDir) assert.NoError(t, err) - files, err := ioutil.ReadDir(homeConfigDir) + files, err := os.ReadDir(homeConfigDir) assert.NoError(t, err) assert.Equal(t, 0, len(files)) - files, err = ioutil.ReadDir(migrateStateDir) + files, err = os.ReadDir(migrateStateDir) assert.NoError(t, err) assert.Equal(t, 1, len(files)) assert.Equal(t, "state.yml", files[0].Name()) diff --git a/internal/oauth2/auth_code_flow.go b/internal/oauth2/auth_code_flow.go index 8eeacf1..8decbbe 100644 --- a/internal/oauth2/auth_code_flow.go +++ b/internal/oauth2/auth_code_flow.go @@ -3,7 +3,9 @@ package oauth2 import ( "bufio" "context" + "errors" "fmt" + "github.com/instill-ai/cli/internal/build" "io" "net/http" "os" @@ -11,6 +13,7 @@ import ( "strings" "time" + "github.com/coreos/go-oidc/v3/oidc" "github.com/instill-ai/cli/api" "github.com/instill-ai/cli/pkg/cmdutil" "github.com/instill-ai/cli/pkg/iostreams" @@ -23,9 +26,13 @@ import ( var ( // The "Instill CLI" OAuth app - oauthClientID = "" - // This value i s safe to be embedded in version control - oauthClientSecret = "" + clientID string + clientSecret string + issuer string + audience string + hostname string + callbackHost string + callbackPort string ) type iconfig interface { @@ -34,39 +41,89 @@ type iconfig interface { Write() error } -// AuthCodeFlowWithConfig authorizes a user via Authorization Code Flow -func AuthCodeFlowWithConfig(f *cmdutil.Factory, cfg iconfig, IO *iostreams.IOStreams, hostname string) error { +// Authenticator is used to authenticate our users. +type Authenticator struct { + *oidc.Provider + oauth2.Config +} - serverHost := "localhost" - serverPort := 8085 +// NewAuthenticator instantiates the *Authenticator. +func NewAuthenticator(issuer, clientID, clientSecret, callbackHost string, callbackPort int) (*Authenticator, error) { + provider, err := oidc.NewProvider(context.Background(), issuer) + if err != nil { + return nil, err + } - fmt.Fprintf(IO.Out, "Login to %s. Press ctrl + c to end the process.\n\n", hostname) + conf := oauth2.Config{ + ClientID: clientID, + ClientSecret: clientSecret, + Endpoint: provider.Endpoint(), + RedirectURL: fmt.Sprintf("http://%s:%d/%s", callbackHost, callbackPort, "callback"), + Scopes: []string{"offline", "openid", "email", "profile"}, + } + + return &Authenticator{ + Provider: provider, + Config: conf, + }, nil +} - conf := &oauth2.Config{ - ClientID: oauthClientID, - ClientSecret: oauthClientSecret, - Endpoint: oauth2.Endpoint{ - AuthURL: fmt.Sprintf("https://auth.%s/oauth2/auth", hostname), - TokenURL: fmt.Sprintf("https://auth.%s/oauth2/token", hostname), - }, - RedirectURL: fmt.Sprintf("http://%s:%d/%s", serverHost, serverPort, "callback"), - Scopes: []string{"offline", "openid", "email", "profile"}, +// VerifyIDToken verifies that an *oauth2.Token is a valid *oidc.IDToken. +func (a *Authenticator) VerifyIDToken(ctx context.Context, token *oauth2.Token) (*oidc.IDToken, error) { + rawIDToken, ok := token.Extra("id_token").(string) + if !ok { + return nil, errors.New("no id_token field in oauth2 token") + } + + oidcConfig := &oidc.Config{ + ClientID: a.ClientID, + } + + return a.Verifier(oidcConfig).Verify(ctx, rawIDToken) +} + +// AuthCodeFlowWithConfig authorizes a user via Authorization Code Flow +func AuthCodeFlowWithConfig(f *cmdutil.Factory, cfg iconfig, IO *iostreams.IOStreams, customHostname string) error { + if customHostname != "" { + return errors.New("TODO handle a custom Core instance") + } + // use env vars in dev mode + if build.Version == "" { + clientID = os.Getenv("INSTILL_OAUTH_CLIENT_ID") + hostname = os.Getenv("INSTILL_OAUTH_HOSTNAME") + audience = os.Getenv("INSTILL_OAUTH_AUDIENCE") + issuer = os.Getenv("INSTILL_OAUTH_ISSUER") + clientSecret = os.Getenv("INSTILL_OAUTH_CLIENT_SECRET") + callbackHost = os.Getenv("INSTILL_OAUTH_CALLBACK_HOST") + callbackPort = os.Getenv("INSTILL_OAUTH_CALLBACK_PORT") + } + cp, err := strconv.Atoi(callbackPort) + if err != nil { + return err + } + port := cp + auth, err := NewAuthenticator(issuer, clientID, clientSecret, callbackHost, port) + if err != nil { + return err } - audience := []string{fmt.Sprintf("https://api.%s", hostname)} prompt := []string{""} maxAge := 0 + loginURL, state := auth.LoginURL([]string{audience}, prompt, maxAge) - authCodeURL, state := generateAuthCodeURL(conf, audience, prompt, maxAge) - fmt.Fprintf(IO.Out, "Complete the login via your OIDC provider. Launching a browser to:\n\n\t%s\n\n", authCodeURL) + fmt.Fprintf(IO.Out, "Login to %s. Press ctrl + c to end the process.\n\n", hostname) + fmt.Fprintf(IO.Out, "Complete the login via your OIDC provider. Launching a browser to:\n\n\t%s\n\n", loginURL) - if err := f.Browser.Browse(authCodeURL); err != nil { + if err := f.Browser.Browse(loginURL); err != nil { return err } - tokenChen := make(chan *oauth2.Token) - go setLocalAuthServer("localhost", 8085, conf, state, IO, tokenChen) - token := <-tokenChen + tokenChan := make(chan *oauth2.Token) + go handleCallback(auth, callbackHost, port, state, IO, tokenChan) + token := <-tokenChan + if token == nil { + return errors.New("error receiving the token") + } if verbose := os.Getenv("DEBUG"); strings.Contains(verbose, "oauth") { fmt.Fprintf(IO.Out, "[DEBUG] Token Type:\n\t%s\n", token.Type()) @@ -101,20 +158,21 @@ func AuthCodeFlowWithConfig(f *cmdutil.Factory, cfg iconfig, IO *iostreams.IOStr } fmt.Fprintf(IO.Out, "%s Authentication complete. %s to continue...\n", IO.ColorScheme().SuccessIcon(), IO.ColorScheme().Bold("Press Enter")) - _ = waitForEnter(IO.In) + _ = waitForInput(IO.In) return nil } -func generateAuthCodeURL(conf *oauth2.Config, audience []string, prompt []string, maxAge int) (string, []rune) { +func (a *Authenticator) LoginURL(audience []string, prompt []string, maxAge int) (string, []rune) { - state, err := randx.RuneSequence(24, randx.AlphaLower) + state, err := randx.RuneSequence(32, randx.AlphaLower) cmdx.Must(err, "Could not generate random state: %s", err) - nonce, err := randx.RuneSequence(24, randx.AlphaLower) + // TODO redundant? + nonce, err := randx.RuneSequence(32, randx.AlphaLower) cmdx.Must(err, "Could not generate random state: %s", err) - authCodeURL := conf.AuthCodeURL( + authCodeURL := a.AuthCodeURL( string(state), oauth2.SetAuthURLParam("audience", strings.Join(audience, "+")), oauth2.SetAuthURLParam("nonce", string(nonce)), @@ -126,9 +184,9 @@ func generateAuthCodeURL(conf *oauth2.Config, audience []string, prompt []string return authCodeURL, state } -func setLocalAuthServer(serverHost string, serverPort int, conf *oauth2.Config, state []rune, IO *iostreams.IOStreams, tokenChan chan *oauth2.Token) { +func handleCallback(auth *Authenticator, serverHost string, serverPort int, state []rune, IO *iostreams.IOStreams, tokenChan chan *oauth2.Token) { - var err error + //var err error var token *oauth2.Token ctx, cancel := context.WithCancel(context.Background()) @@ -172,7 +230,8 @@ func setLocalAuthServer(serverHost string, serverPort int, conf *oauth2.Config, fmt.Printf("[DEBUG] Exchange code:\n\t%s\n", code) } - token, err = conf.Exchange(ctx, code) + // Exchange an authorization code for a token. + token, err := auth.Exchange(ctx, code) if err != nil { fmt.Fprintf(IO.ErrOut, "Unable to exchange code for token: %s\n", err) tokenChan <- token @@ -180,6 +239,14 @@ func setLocalAuthServer(serverHost string, serverPort int, conf *oauth2.Config, cancel() return } + _, err = auth.VerifyIDToken(ctx, token) + if err != nil { + fmt.Fprintf(IO.ErrOut, "Unable to validate token: %s\n", err) + tokenChan <- token + close(tokenChan) + cancel() + return + } fmt.Fprint(w, oauthSuccessPage) @@ -204,7 +271,7 @@ func setLocalAuthServer(serverHost string, serverPort int, conf *oauth2.Config, } } -func waitForEnter(r io.Reader) error { +func waitForInput(r io.Reader) error { scanner := bufio.NewScanner(r) scanner.Scan() return scanner.Err() diff --git a/internal/oauth2/refresh_token.go b/internal/oauth2/refresh_token.go index 5e9f7bb..f840aa6 100644 --- a/internal/oauth2/refresh_token.go +++ b/internal/oauth2/refresh_token.go @@ -42,8 +42,8 @@ func RefreshToken(cfg iconfig, hostname string) (string, error) { } conf := &oauth2.Config{ - ClientID: oauthClientID, - ClientSecret: oauthClientSecret, + ClientID: clientID, + ClientSecret: clientSecret, Endpoint: oauth2.Endpoint{ AuthURL: fmt.Sprintf("https://auth.%s/oauth2/auth", hostname), TokenURL: fmt.Sprintf("https://auth.%s/oauth2/token", hostname), diff --git a/internal/update/update.go b/internal/update/update.go index bec2f89..a663076 100644 --- a/internal/update/update.go +++ b/internal/update/update.go @@ -2,7 +2,6 @@ package update import ( "fmt" - "io/ioutil" "os" "path/filepath" "regexp" @@ -64,7 +63,7 @@ func getLatestReleaseInfo(client *api.Client, repo string) (*ReleaseInfo, error) } func getStateEntry(stateFilePath string) (*StateEntry, error) { - content, err := ioutil.ReadFile(stateFilePath) + content, err := os.ReadFile(stateFilePath) if err != nil { return nil, err } @@ -90,7 +89,7 @@ func setStateEntry(stateFilePath string, t time.Time, r ReleaseInfo) error { return err } - err = ioutil.WriteFile(stateFilePath, content, 0600) + err = os.WriteFile(stateFilePath, content, 0600) return err } diff --git a/internal/update/update_test.go b/internal/update/update_test.go index 6865a5b..511f46d 100644 --- a/internal/update/update_test.go +++ b/internal/update/update_test.go @@ -2,9 +2,8 @@ package update import ( "fmt" - "io/ioutil" "log" - "os" + os "os" "testing" "github.com/instill-ai/cli/api" @@ -117,7 +116,7 @@ func TestCheckForUpdate(t *testing.T) { } func tempFilePath() string { - file, err := ioutil.TempFile("", "") + file, err := os.CreateTemp("", "") if err != nil { log.Fatal(err) } diff --git a/pkg/cmd/api/api.go b/pkg/cmd/api/api.go index a19672c..6e0f7c1 100644 --- a/pkg/cmd/api/api.go +++ b/pkg/cmd/api/api.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net/http" "os" "regexp" @@ -190,7 +189,7 @@ func apiRun(opts *ApiOptions) error { headersOutputStream := opts.IO.Out if opts.Silent { - opts.IO.Out = ioutil.Discard + opts.IO.Out = io.Discard } else { err := opts.IO.StartPager() if err != nil { @@ -382,7 +381,7 @@ func openUserFile(fn string, stdin io.ReadCloser) (io.ReadCloser, int64, error) func parseErrorResponse(r io.Reader, statusCode int) (io.Reader, string, error) { bodyCopy := &bytes.Buffer{} - b, err := ioutil.ReadAll(io.TeeReader(r, bodyCopy)) + b, err := io.ReadAll(io.TeeReader(r, bodyCopy)) if err != nil { return r, "", err } diff --git a/pkg/cmd/api/api_test.go b/pkg/cmd/api/api_test.go index 9d4637a..1c5501a 100644 --- a/pkg/cmd/api/api_test.go +++ b/pkg/cmd/api/api_test.go @@ -3,7 +3,7 @@ package api import ( "bytes" "fmt" - "io/ioutil" + "io" "net/http" "os" "path/filepath" @@ -243,7 +243,7 @@ func Test_apiRun(t *testing.T) { name: "success", httpResponse: &http.Response{ StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewBufferString(`bam!`)), + Body: io.NopCloser(bytes.NewBufferString(`bam!`)), }, err: nil, stdout: `bam!`, @@ -258,7 +258,7 @@ func Test_apiRun(t *testing.T) { Proto: "HTTP/1.1", Status: "200 Okey-dokey", StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewBufferString(`body`)), + Body: io.NopCloser(bytes.NewBufferString(`body`)), Header: http.Header{"Content-Type": []string{"text/plain"}}, }, err: nil, @@ -279,7 +279,7 @@ func Test_apiRun(t *testing.T) { name: "REST error", httpResponse: &http.Response{ StatusCode: 400, - Body: ioutil.NopCloser(bytes.NewBufferString(`{"message": "THIS IS FINE"}`)), + Body: io.NopCloser(bytes.NewBufferString(`{"message": "THIS IS FINE"}`)), Header: http.Header{"Content-Type": []string{"application/json; charset=utf-8"}}, }, err: cmdutil.SilentError, @@ -290,7 +290,7 @@ func Test_apiRun(t *testing.T) { name: "REST string errors", httpResponse: &http.Response{ StatusCode: 400, - Body: ioutil.NopCloser(bytes.NewBufferString(`{"errors": ["ALSO", "FINE"]}`)), + Body: io.NopCloser(bytes.NewBufferString(`{"errors": ["ALSO", "FINE"]}`)), Header: http.Header{"Content-Type": []string{"application/json; charset=utf-8"}}, }, err: cmdutil.SilentError, @@ -301,7 +301,7 @@ func Test_apiRun(t *testing.T) { name: "failure", httpResponse: &http.Response{ StatusCode: 502, - Body: ioutil.NopCloser(bytes.NewBufferString(`gateway timeout`)), + Body: io.NopCloser(bytes.NewBufferString(`gateway timeout`)), }, err: cmdutil.SilentError, stdout: `gateway timeout`, @@ -314,7 +314,7 @@ func Test_apiRun(t *testing.T) { }, httpResponse: &http.Response{ StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewBufferString(`body`)), + Body: io.NopCloser(bytes.NewBufferString(`body`)), }, err: nil, stdout: ``, @@ -330,7 +330,7 @@ func Test_apiRun(t *testing.T) { Proto: "HTTP/1.1", Status: "200 Okey-dokey", StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewBufferString(`body`)), + Body: io.NopCloser(bytes.NewBufferString(`body`)), Header: http.Header{"Content-Type": []string{"text/plain"}}, }, err: nil, @@ -344,7 +344,7 @@ func Test_apiRun(t *testing.T) { }, httpResponse: &http.Response{ StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewBufferString(`{"status":"not a cat"}`)), + Body: io.NopCloser(bytes.NewBufferString(`{"status":"not a cat"}`)), Header: http.Header{"Content-Type": []string{"application/json"}}, }, err: nil, @@ -358,7 +358,7 @@ func Test_apiRun(t *testing.T) { }, httpResponse: &http.Response{ StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewBufferString(`[{"name":"Mona"},{"name":"Hubot"}]`)), + Body: io.NopCloser(bytes.NewBufferString(`[{"name":"Mona"},{"name":"Hubot"}]`)), Header: http.Header{"Content-Type": []string{"application/json"}}, }, err: nil, @@ -369,9 +369,9 @@ func Test_apiRun(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - io, _, stdout, stderr := iostreams.Test() + stream, _, stdout, stderr := iostreams.Test() - tt.options.IO = io + tt.options.IO = stream tt.options.Config = func() (config.Config, error) { return config.NewBlankConfig(), nil } tt.options.HTTPClient = func() (*http.Client, error) { var tr roundTripper = func(req *http.Request) (*http.Response, error) { @@ -424,14 +424,14 @@ func Test_apiRun_inputFile(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - io, stdin, _, _ := iostreams.Test() + stream, stdin, _, _ := iostreams.Test() resp := &http.Response{StatusCode: 204} inputFile := tt.inputFile if tt.inputFile == "-" { _, _ = stdin.Write(tt.inputContents) } else { - f, err := ioutil.TempFile(tempDir, tt.inputFile) + f, err := os.CreateTemp(tempDir, tt.inputFile) if err != nil { t.Fatal(err) } @@ -446,11 +446,11 @@ func Test_apiRun_inputFile(t *testing.T) { RequestInputFile: inputFile, RawFields: []string{"a=b", "c=d"}, - IO: io, + IO: stream, HTTPClient: func() (*http.Client, error) { var tr roundTripper = func(req *http.Request) (*http.Response, error) { var err error - if bodyBytes, err = ioutil.ReadAll(req.Body); err != nil { + if bodyBytes, err = io.ReadAll(req.Body); err != nil { return nil, err } resp.Request = req @@ -478,11 +478,11 @@ func Test_apiRun_inputFile(t *testing.T) { } func Test_apiRun_cache(t *testing.T) { - io, _, stdout, stderr := iostreams.Test() + stream, _, stdout, stderr := iostreams.Test() requestCount := 0 options := ApiOptions{ - IO: io, + IO: stream, HTTPClient: func() (*http.Client, error) { var tr roundTripper = func(req *http.Request) (*http.Response, error) { requestCount++ @@ -517,11 +517,11 @@ func Test_apiRun_cache(t *testing.T) { } func Test_parseFields(t *testing.T) { - io, stdin, _, _ := iostreams.Test() + stream, stdin, _, _ := iostreams.Test() fmt.Fprint(stdin, "pasted contents") opts := ApiOptions{ - IO: io, + IO: stream, RawFields: []string{ "robot=Hubot", "destroyer=false", @@ -553,7 +553,7 @@ func Test_parseFields(t *testing.T) { } func Test_magicFieldValue(t *testing.T) { - f, err := ioutil.TempFile(t.TempDir(), "instill-test") + f, err := os.CreateTemp(t.TempDir(), "instill-test") if err != nil { t.Fatal(err) } @@ -561,7 +561,7 @@ func Test_magicFieldValue(t *testing.T) { fmt.Fprint(f, "file contents") - io, _, _, _ := iostreams.Test() + stream, _, _, _ := iostreams.Test() type args struct { v string @@ -601,7 +601,7 @@ func Test_magicFieldValue(t *testing.T) { name: "file", args: args{ v: "@" + f.Name(), - opts: &ApiOptions{IO: io}, + opts: &ApiOptions{IO: stream}, }, want: []byte("file contents"), wantErr: false, @@ -610,7 +610,7 @@ func Test_magicFieldValue(t *testing.T) { name: "file error", args: args{ v: "@", - opts: &ApiOptions{IO: io}, + opts: &ApiOptions{IO: stream}, }, want: nil, wantErr: true, @@ -632,7 +632,7 @@ func Test_magicFieldValue(t *testing.T) { } func Test_openUserFile(t *testing.T) { - f, err := ioutil.TempFile(t.TempDir(), "instill-test") + f, err := os.CreateTemp(t.TempDir(), "instill-test") if err != nil { t.Fatal(err) } @@ -646,7 +646,7 @@ func Test_openUserFile(t *testing.T) { } defer file.Close() - fb, err := ioutil.ReadAll(file) + fb, err := io.ReadAll(file) if err != nil { t.Fatal(err) } @@ -656,14 +656,14 @@ func Test_openUserFile(t *testing.T) { } func Test_processResponse_template(t *testing.T) { - io, _, stdout, stderr := iostreams.Test() + stream, _, stdout, stderr := iostreams.Test() resp := http.Response{ StatusCode: 200, Header: map[string][]string{ "Content-Type": {"application/json"}, }, - Body: ioutil.NopCloser(strings.NewReader(`[ + Body: io.NopCloser(strings.NewReader(`[ { "title": "First title", "labels": [{"name":"bug"}, {"name":"help wanted"}] @@ -679,11 +679,11 @@ func Test_processResponse_template(t *testing.T) { } opts := ApiOptions{ - IO: io, + IO: stream, Template: `{{range .}}{{.title}} ({{.labels | pluck "name" | join ", " }}){{"\n"}}{{end}}`, } - template := export.NewTemplate(io, opts.Template) - err := processResponse(&resp, &opts, ioutil.Discard, &template) + template := export.NewTemplate(stream, opts.Template) + err := processResponse(&resp, &opts, io.Discard, &template) require.NoError(t, err) err = template.End() diff --git a/pkg/cmd/api/http.go b/pkg/cmd/api/http.go index ac90ad5..910d272 100644 --- a/pkg/cmd/api/http.go +++ b/pkg/cmd/api/http.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "net/url" "strconv" @@ -50,7 +49,7 @@ func httpRequest(client *http.Client, hostname string, method string, p string, } } case io.Reader: - if data, err := ioutil.ReadAll(pp); err == nil { + if data, err := io.ReadAll(pp); err == nil { // Check if body data is JSON if json.Valid(data) { bodyIsJSON = true diff --git a/pkg/cmd/api/http_test.go b/pkg/cmd/api/http_test.go index 2188112..545702f 100644 --- a/pkg/cmd/api/http_test.go +++ b/pkg/cmd/api/http_test.go @@ -2,7 +2,7 @@ package api import ( "bytes" - "io/ioutil" + "io" "net/http" "testing" ) @@ -153,7 +153,7 @@ func Test_httpRequest(t *testing.T) { } if tt.want.body != "" { - bb, err := ioutil.ReadAll(req.Body) + bb, err := io.ReadAll(req.Body) if err != nil { t.Errorf("Request.Body ReadAll error = %v", err) return diff --git a/pkg/cmd/auth/login/login.go b/pkg/cmd/auth/login/login.go index 2e1ad60..263f37b 100644 --- a/pkg/cmd/auth/login/login.go +++ b/pkg/cmd/auth/login/login.go @@ -81,9 +81,6 @@ func loginRun(f *cmdutil.Factory, opts *LoginOptions) error { } hostname := opts.Hostname - if hostname == "" { - hostname = instance.Default() - } if err := cfg.CheckWriteable(hostname, ""); err != nil { return err @@ -109,7 +106,7 @@ func loginRun(f *cmdutil.Factory, opts *LoginOptions) error { return shared.Login(f, &shared.LoginOptions{ IO: opts.IO, Config: cfg, - Hostname: hostname, + Hostname: opts.Hostname, Interactive: opts.Interactive, Executable: opts.MainExecutable, }) diff --git a/pkg/cmdutil/file_input.go b/pkg/cmdutil/file_input.go index 32322bc..e4cfd21 100644 --- a/pkg/cmdutil/file_input.go +++ b/pkg/cmdutil/file_input.go @@ -2,15 +2,15 @@ package cmdutil import ( "io" - "io/ioutil" + "os" ) func ReadFile(filename string, stdin io.ReadCloser) ([]byte, error) { if filename == "-" { - b, err := ioutil.ReadAll(stdin) + b, err := io.ReadAll(stdin) _ = stdin.Close() return b, err } - return ioutil.ReadFile(filename) + return os.ReadFile(filename) } diff --git a/pkg/cmdutil/json_flags_test.go b/pkg/cmdutil/json_flags_test.go index 886740b..4271eae 100644 --- a/pkg/cmdutil/json_flags_test.go +++ b/pkg/cmdutil/json_flags_test.go @@ -3,7 +3,7 @@ package cmdutil import ( "bytes" "fmt" - "io/ioutil" + "io" "testing" "github.com/spf13/cobra" @@ -100,8 +100,8 @@ func TestAddJSONFlags(t *testing.T) { var exporter Exporter AddJSONFlags(cmd, &exporter, tt.fields) cmd.SetArgs(tt.args) - cmd.SetOut(ioutil.Discard) - cmd.SetErr(ioutil.Discard) + cmd.SetOut(io.Discard) + cmd.SetErr(io.Discard) _, err := cmd.ExecuteC() if tt.wantsError == "" { require.NoError(t, err) diff --git a/pkg/export/filter.go b/pkg/export/filter.go index 514fd48..e801576 100644 --- a/pkg/export/filter.go +++ b/pkg/export/filter.go @@ -3,10 +3,8 @@ package export import ( "encoding/json" "fmt" - "io" - "io/ioutil" - "github.com/itchyny/gojq" + "io" ) func FilterJSON(w io.Writer, input io.Reader, queryStr string) error { @@ -15,7 +13,7 @@ func FilterJSON(w io.Writer, input io.Reader, queryStr string) error { return err } - jsonData, err := ioutil.ReadAll(input) + jsonData, err := io.ReadAll(input) if err != nil { return err } diff --git a/pkg/export/template.go b/pkg/export/template.go index d8ce890..518a8ca 100644 --- a/pkg/export/template.go +++ b/pkg/export/template.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "math" "strconv" "strings" @@ -82,7 +81,7 @@ func (t *Template) Execute(input io.Reader) error { t.template = template } - jsonData, err := ioutil.ReadAll(input) + jsonData, err := io.ReadAll(input) if err != nil { return err } diff --git a/pkg/httpmock/stub.go b/pkg/httpmock/stub.go index a2c7a31..66d10fd 100644 --- a/pkg/httpmock/stub.go +++ b/pkg/httpmock/stub.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "io" - "io/ioutil" "net/http" "os" "strings" @@ -38,8 +37,8 @@ func REST(method, p string) Matcher { func readBody(req *http.Request) ([]byte, error) { bodyCopy := &bytes.Buffer{} r := io.TeeReader(req.Body, bodyCopy) - req.Body = ioutil.NopCloser(bodyCopy) - return ioutil.ReadAll(r) + req.Body = io.NopCloser(bodyCopy) + return io.ReadAll(r) } func decodeJSONBody(req *http.Request, dest interface{}) error { @@ -99,7 +98,7 @@ func ScopesResponder(scopes string) func(*http.Request) (*http.Response, error) Header: map[string][]string{ "X-Oauth-Scopes": {scopes}, }, - Body: ioutil.NopCloser(bytes.NewBufferString("")), + Body: io.NopCloser(bytes.NewBufferString("")), }, nil } } @@ -108,7 +107,7 @@ func httpResponse(status int, req *http.Request, body io.Reader) *http.Response return &http.Response{ StatusCode: status, Request: req, - Body: ioutil.NopCloser(body), + Body: io.NopCloser(body), Header: http.Header{}, } } diff --git a/pkg/iostreams/iostreams.go b/pkg/iostreams/iostreams.go index e071114..9d34e39 100644 --- a/pkg/iostreams/iostreams.go +++ b/pkg/iostreams/iostreams.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "os" "os/exec" "strconv" @@ -353,14 +352,14 @@ func (s *IOStreams) ReadUserFile(fn string) ([]byte, error) { } } defer r.Close() - return ioutil.ReadAll(r) + return io.ReadAll(r) } func (s *IOStreams) TempFile(dir, pattern string) (*os.File, error) { if s.TempFileOverride != nil { return s.TempFileOverride, nil } - return ioutil.TempFile(dir, pattern) + return os.CreateTemp(dir, pattern) } func System() *IOStreams { @@ -401,7 +400,7 @@ func Test() (*IOStreams, *bytes.Buffer, *bytes.Buffer, *bytes.Buffer) { out := &bytes.Buffer{} errOut := &bytes.Buffer{} return &IOStreams{ - In: ioutil.NopCloser(in), + In: io.NopCloser(in), Out: out, ErrOut: errOut, ttySize: func() (int, int, error) { diff --git a/pkg/surveyext/editor_manual.go b/pkg/surveyext/editor_manual.go index 93572ba..10e3e63 100644 --- a/pkg/surveyext/editor_manual.go +++ b/pkg/surveyext/editor_manual.go @@ -3,7 +3,6 @@ package surveyext import ( "bytes" "io" - "io/ioutil" "os" "os/exec" @@ -33,7 +32,7 @@ func edit(editorCommand, fn, initialValue string, stdin io.Reader, stdout io.Wri if pattern == "" { pattern = "survey*.txt" } - f, err := ioutil.TempFile("", pattern) + f, err := os.CreateTemp("", pattern) if err != nil { return "", err } @@ -90,7 +89,7 @@ func edit(editorCommand, fn, initialValue string, stdin io.Reader, stdout io.Wri } // raw is a BOM-unstripped UTF8 byte slice - raw, err := ioutil.ReadFile(f.Name()) + raw, err := os.ReadFile(f.Name()) if err != nil { return "", err } diff --git a/script/build.go b/script/build.go index 53abdd0..f613cd3 100644 --- a/script/build.go +++ b/script/build.go @@ -10,6 +10,11 @@ // - INSTILL_VERSION: determined from source by default // - INSTILL_OAUTH_CLIENT_ID // - INSTILL_OAUTH_CLIENT_SECRET +// - INSTILL_OAUTH_HOSTNAME +// - INSTILL_OAUTH_AUDIENCE +// - INSTILL_OAUTH_ISSUER +// - INSTILL_OAUTH_CALLBACK_HOST +// - INSTILL_OAUTH_CALLBACK_PORT // - SOURCE_DATE_EPOCH: enables reproducible builds // - GO_LDFLAGS // @@ -25,7 +30,10 @@ package main import ( "errors" "fmt" - "io/ioutil" + "github.com/cli/safeexec" + "github.com/dotenv-org/godotenvvault" + "io" + "log" "os" "os/exec" "path/filepath" @@ -33,10 +41,18 @@ import ( "strconv" "strings" "time" - - "github.com/cli/safeexec" ) +var oauthFields = [][]string{ + {"INSTILL_OAUTH_CLIENT_SECRET", "clientSecret"}, + {"INSTILL_OAUTH_CLIENT_ID", "clientID"}, + {"INSTILL_OAUTH_ISSUER", "issuer"}, + {"INSTILL_OAUTH_HOSTNAME", "hostname"}, + {"INSTILL_OAUTH_AUDIENCE", "audience"}, + {"INSTILL_OAUTH_CALLBACK_HOST", "callbackHost"}, + {"INSTILL_OAUTH_CALLBACK_PORT", "callbackPort"}, +} + var tasks = map[string]func(string) error{ "bin/instill": func(exe string) error { info, err := os.Stat(exe) @@ -48,9 +64,13 @@ var tasks = map[string]func(string) error{ ldflags := os.Getenv("GO_LDFLAGS") ldflags = fmt.Sprintf("-X github.com/instill-ai/cli/internal/build.Version=%s %s", version(), ldflags) ldflags = fmt.Sprintf("-X github.com/instill-ai/cli/internal/build.Date=%s %s", date(), ldflags) - if oauthSecret := os.Getenv("INSTILL_OAUTH_CLIENT_SECRET"); oauthSecret != "" { - ldflags = fmt.Sprintf("-X github.com/instill-ai/cli/internal/oauth2.oauthClientSecret=%s %s", oauthSecret, ldflags) - ldflags = fmt.Sprintf("-X github.com/instill-ai/cli/internal/oauth2.oauthClientID=%s %s", os.Getenv("INSTILL_OAUTH_CLIENT_ID"), ldflags) + oauthSecret := os.Getenv(oauthFields[0][0]) + if oauthSecret != "" { + for _, v := range oauthFields { + nameEnv, nameVar := v[0], v[1] + ldflags = fmt.Sprintf("-X github.com/instill-ai/cli/internal/oauth2.%s=%s %s", + nameVar, os.Getenv(nameEnv), ldflags) + } } return run("go", "build", "-trimpath", "-ldflags", ldflags, "-o", exe, "./cmd/instill") @@ -63,6 +83,10 @@ var tasks = map[string]func(string) error{ var self string func main() { + err := godotenvvault.Load() + if err != nil { + log.Fatal("Error loading .env file") + } args := os.Args[:1] for _, arg := range os.Args[1:] { if idx := strings.IndexRune(arg, '='); idx >= 0 { @@ -212,7 +236,7 @@ func cmdOutput(args ...string) (string, error) { return "", err } cmd := exec.Command(exe, args[1:]...) - cmd.Stderr = ioutil.Discard + cmd.Stderr = io.Discard out, err := cmd.Output() return strings.TrimSuffix(string(out), "\n"), err }