diff --git a/.github/win/windows-installer-v8-x64.iss b/.github/win/windows-installer-v8-x64.iss index c11acb04151..29f8f652d03 100644 --- a/.github/win/windows-installer-v8-x64.iss +++ b/.github/win/windows-installer-v8-x64.iss @@ -5,8 +5,8 @@ AppName=Cloud Foundry CLI AppVersion=VERSION AppVerName=Cloud Foundry CLI version VERSION AppPublisher=Cloud Foundry Foundation -ArchitecturesInstallIn64BitMode=x64 ia64 -ArchitecturesAllowed=x64 ia64 +ArchitecturesInstallIn64BitMode=x64compatible +ArchitecturesAllowed=x64compatible PrivilegesRequired=none DefaultDirName={pf}\Cloud Foundry SetupIconFile=cf.ico diff --git a/.github/workflows/check-cves.yml b/.github/workflows/check-cves.yml index cef3430824f..657ca5d3ac3 100644 --- a/.github/workflows/check-cves.yml +++ b/.github/workflows/check-cves.yml @@ -13,7 +13,7 @@ jobs: uses: actions/checkout@v4 - name: Scan current project - uses: anchore/scan-action@v3 + uses: anchore/scan-action@v4 with: path: "." add-cpes-if-none: true diff --git a/.github/workflows/release-build-sign-upload.yml b/.github/workflows/release-build-sign-upload.yml index 754de9566d6..911a1348a32 100644 --- a/.github/workflows/release-build-sign-upload.yml +++ b/.github/workflows/release-build-sign-upload.yml @@ -36,7 +36,6 @@ run-name: "Release: Build Sign Upload [${{ github.ref_name }}]" # SIGNING_KEY_WINDOWS_PASSPHRASE # SIGNING_KEY_WINDOWS_PFX - on: workflow_dispatch: @@ -44,41 +43,12 @@ permissions: contents: read defaults: - # top-level defaults subkeys apply to jobs - # run subkeys apply to all steps within all jobs run: shell: bash jobs: - - # test: - # environment: DEV - # runs-on: ubuntu-latest - # steps: - # - name: Setup upterm session - # env: - # AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - # AWS_REGION: ${{ secrets.AWS_REGION }} - # AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - # GIT_RELEASE_TARGET_REPO: ${{ secrets.GIT_RELEASE_TARGET_REPO }} - # GIT_REPO_ACCESS_TOKEN: ${{ secrets.GIT_REPO_ACCESS_TOKEN }} - # SIGNING_KEY_GPG: ${{ secrets.SIGNING_KEY_GPG }} - # SIGNING_KEY_GPG_ID: ${{ secrets.SIGNING_KEY_GPG_ID }} - # SIGNING_KEY_GPG_PASSPHRASE: ${{ secrets.SIGNING_KEY_GPG_PASSPHRASE }} - # SIGNING_KEY_MAC_ID: ${{ secrets.SIGNING_KEY_MAC_ID }} - # SIGNING_KEY_MAC_PASSPHRASE: ${{ secrets.SIGNING_KEY_MAC_PASSPHRASE }} - # SIGNING_KEY_MAC_PFX: ${{ secrets.SIGNING_KEY_MAC_PFX }} - # SIGNING_KEY_WINDOWS_ID: ${{ secrets.SIGNING_KEY_WINDOWS_ID }} - # SIGNING_KEY_WINDOWS_PASSPHRASE: ${{ secrets.SIGNING_KEY_WINDOWS_PASSPHRASE }} - # SIGNING_KEY_WINDOWS_PFX: ${{ secrets.SIGNING_KEY_WINDOWS_PFX }} - # SIGNING_TEST_CA_MAC: ${{ secrets.SIGNING_TEST_CA_MAC }} - # if: always() - # uses: lhotari/action-upterm@v1 - # timeout-minutes: 60 - setup: name: Setup - # needs: test runs-on: ubuntu-latest outputs: @@ -673,24 +643,6 @@ jobs: smctl windows certsync shell: cmd - # This is for debugging windows - # - name: enable ssh - # if: always() - # run: | - # Get-WindowsCapability -Online - # $componentName = $(Get-WindowsCapability -Online |Where-Object Name -like 'OpenSSH.Server*').Name - # Add-WindowsCapability -Online -Name $componentName - # Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" - - # - name: ssh session - # if: always() - # run: | - # Start-Service sshd - # echo "IP address below:" - # Get-NetIPAddress | Select-Object -Property IPAddress - # sleep 3600 - # Stop-Service sshd - - name: Sign Windows binaries run: | smctl healthcheck --all @@ -754,9 +706,6 @@ jobs: popd Get-ChildItem "${env:RUNNER_TEMP}" - # - name: Setup tmate session - # uses: mxschmitt/action-tmate@v3 - - name: Save installer and dist files as a GitHub Action Artifact uses: actions/upload-artifact@v4 with: @@ -1009,28 +958,30 @@ jobs: github-release-draft: name: Create GitHub Release Draft runs-on: ubuntu-latest + env: + REPO_DIR: repo + ARTIFACTS_DIR: artifacts permissions: actions: read contents: write needs: - setup - - test-rpm-package - - test-deb-package - - test-macos - - test-windows + - s3-upload steps: - name: Download signed artifacts uses: actions/download-artifact@v4 with: name: final-artifacts - path: artifacts # download all artifacts to 'artifacts/' + path: ${{ env.ARTIFACTS_DIR }} - name: Checkout CLI uses: actions/checkout@v4 - + with: + path: ${{ env.REPO_DIR }} + - name: Prepare release notes run: | - sed -i 's/new-version/${{ needs.setup.outputs.version-build }}/g' .github/release/release-notes-template.txt + sed -i 's/new-version/${{ needs.setup.outputs.version-build }}/g' "${{ env.REPO_DIR }}/.github/release/release-notes-template.txt" - name: Create draft release uses: softprops/action-gh-release@v2 @@ -1038,22 +989,22 @@ jobs: draft: true name: "DRAFT v${{ needs.setup.outputs.version-build }}" tag_name: "v${{ needs.setup.outputs.version-build }}" - body_path: ".github/release/release-notes-template.txt" + body_path: "${{ env.REPO_DIR }}/.github/release/release-notes-template.txt" fail_on_unmatched_files: true generate_release_notes: true files: | - artifacts/cf-cli-linux-rpm-packages/cf*rpm - artifacts/cf-cli-linux-deb-packages/cf*deb - artifacts/cf-cli-macos-packages/cf*pkg - artifacts/cf-cli-windows-packages/cf*zip - artifacts/linux_i686/*tgz - artifacts/linux_x86-64/*tgz - artifacts/linux_arm64/*tgz - artifacts/osx/*tgz - artifacts/macosarm/*tgz - artifacts/win32/*zip - artifacts/winx64/*zip - + ${{ env.ARTIFACTS_DIR }}/cf-cli-linux-rpm-packages/cf*rpm + ${{ env.ARTIFACTS_DIR }}/cf-cli-linux-deb-packages/cf*deb + ${{ env.ARTIFACTS_DIR }}/cf-cli-macos-packages/cf*pkg + ${{ env.ARTIFACTS_DIR }}/cf-cli-windows-packages/cf*zip + ${{ env.ARTIFACTS_DIR }}/linux_i686/*tgz + ${{ env.ARTIFACTS_DIR }}/linux_x86-64/*tgz + ${{ env.ARTIFACTS_DIR }}/linux_arm64/*tgz + ${{ env.ARTIFACTS_DIR }}/osx/*tgz + ${{ env.ARTIFACTS_DIR }}/macosarm/*tgz + ${{ env.ARTIFACTS_DIR }}/win32/*zip + ${{ env.ARTIFACTS_DIR }}/winx64/*zip + update-claw: name: Add new release version to CLAW runs-on: ubuntu-latest @@ -1094,5 +1045,4 @@ jobs: git push fi - popd -# vim: set sw=2 ts=2 sts=2 et tw=78 foldlevel=2 fdm=indent nospell: + popd \ No newline at end of file diff --git a/cf/api/buildpack_bits.go b/cf/api/buildpack_bits.go index a3dd4416071..da6efd357eb 100644 --- a/cf/api/buildpack_bits.go +++ b/cf/api/buildpack_bits.go @@ -108,6 +108,7 @@ func (repo CloudControllerBuildpackBitsRepository) CreateBuildpackZipFile(buildp if err != nil { return nil, "", fmt.Errorf("%s: %s", T("Couldn't open buildpack file"), err.Error()) } + defer specifiedFile.Close() err = normalizeBuildpackArchive(specifiedFile, zipFileToUpload) if err != nil { return nil, "", zipErrorHelper(err) diff --git a/command/commandfakes/fake_ui.go b/command/commandfakes/fake_ui.go index c160f6d0be2..d91cb625272 100644 --- a/command/commandfakes/fake_ui.go +++ b/command/commandfakes/fake_ui.go @@ -174,6 +174,11 @@ type FakeUI struct { arg1 string arg2 []map[string]interface{} } + DisplayTextLiteralStub func(string) + displayTextLiteralMutex sync.RWMutex + displayTextLiteralArgsForCall []struct { + arg1 string + } DisplayTextMenuStub func([]string, string, ...map[string]interface{}) (string, error) displayTextMenuMutex sync.RWMutex displayTextMenuArgsForCall []struct { @@ -1190,6 +1195,38 @@ func (fake *FakeUI) DisplayTextArgsForCall(i int) (string, []map[string]interfac return argsForCall.arg1, argsForCall.arg2 } +func (fake *FakeUI) DisplayTextLiteral(arg1 string) { + fake.displayTextLiteralMutex.Lock() + fake.displayTextLiteralArgsForCall = append(fake.displayTextLiteralArgsForCall, struct { + arg1 string + }{arg1}) + stub := fake.DisplayTextLiteralStub + fake.recordInvocation("DisplayTextLiteral", []interface{}{arg1}) + fake.displayTextLiteralMutex.Unlock() + if stub != nil { + fake.DisplayTextLiteralStub(arg1) + } +} + +func (fake *FakeUI) DisplayTextLiteralCallCount() int { + fake.displayTextLiteralMutex.RLock() + defer fake.displayTextLiteralMutex.RUnlock() + return len(fake.displayTextLiteralArgsForCall) +} + +func (fake *FakeUI) DisplayTextLiteralCalls(stub func(string)) { + fake.displayTextLiteralMutex.Lock() + defer fake.displayTextLiteralMutex.Unlock() + fake.DisplayTextLiteralStub = stub +} + +func (fake *FakeUI) DisplayTextLiteralArgsForCall(i int) string { + fake.displayTextLiteralMutex.RLock() + defer fake.displayTextLiteralMutex.RUnlock() + argsForCall := fake.displayTextLiteralArgsForCall[i] + return argsForCall.arg1 +} + func (fake *FakeUI) DisplayTextMenu(arg1 []string, arg2 string, arg3 ...map[string]interface{}) (string, error) { var arg1Copy []string if arg1 != nil { @@ -1963,6 +2000,8 @@ func (fake *FakeUI) Invocations() map[string][][]interface{} { defer fake.displayTableWithHeaderMutex.RUnlock() fake.displayTextMutex.RLock() defer fake.displayTextMutex.RUnlock() + fake.displayTextLiteralMutex.RLock() + defer fake.displayTextLiteralMutex.RUnlock() fake.displayTextMenuMutex.RLock() defer fake.displayTextMenuMutex.RUnlock() fake.displayTextPromptMutex.RLock() diff --git a/command/ui.go b/command/ui.go index 6c479b8385f..424c71d207a 100644 --- a/command/ui.go +++ b/command/ui.go @@ -33,6 +33,7 @@ type UI interface { DisplayPasswordPrompt(template string, templateValues ...map[string]interface{}) (string, error) DisplayTableWithHeader(prefix string, table [][]string, padding int) DisplayText(template string, data ...map[string]interface{}) + DisplayTextLiteral(text string) DisplayTextMenu(choices []string, promptTemplate string, templateValues ...map[string]interface{}) (string, error) DisplayTextPrompt(template string, templateValues ...map[string]interface{}) (string, error) DisplayTextWithBold(text string, keys ...map[string]interface{}) diff --git a/command/v7/env_command.go b/command/v7/env_command.go index a021cdfc02f..0d924c1473a 100644 --- a/command/v7/env_command.go +++ b/command/v7/env_command.go @@ -93,7 +93,7 @@ func (cmd EnvCommand) displayEnvGroup(group map[string]interface{}) { keys := sortKeys(group) for _, key := range keys { - cmd.UI.DisplayText(fmt.Sprintf("%s: %v", key, group[key])) + cmd.UI.DisplayTextLiteral(fmt.Sprintf("%s: %v", key, group[key])) } } diff --git a/command/v7/env_command_test.go b/command/v7/env_command_test.go index 03a7c1acaed..13ff12e372f 100644 --- a/command/v7/env_command_test.go +++ b/command/v7/env_command_test.go @@ -232,6 +232,42 @@ var _ = Describe("env Command", func() { Expect(testUI.Err).To(Say("get-warning-2")) }) }) + + When("getting the environment returns env vars with special templating characters", func() { + BeforeEach(func() { + envGroups := v7action.EnvironmentVariableGroups{ + System: map[string]interface{}{"system-name": map[string]interface{}{"mysql": []string{"system-value"}, "password": "{{test<3"}}, + Application: map[string]interface{}{"application-name": "{{application-value"}, + EnvironmentVariables: map[string]interface{}{"user-name": "{{user-value"}, + Running: map[string]interface{}{"running-name": "{{running-value"}, + Staging: map[string]interface{}{"staging-name": "{{staging-value"}, + } + fakeActor.GetEnvironmentVariablesByApplicationNameAndSpaceReturns(envGroups, nil, nil) + }) + + It("displays the environment variable and value pair", func() { + Expect(executeErr).ToNot(HaveOccurred()) + + Expect(testUI.Out).To(Say(`Getting env variables for app some-app in org some-org / space some-space as banana\.\.\.`)) + Expect(testUI.Out).To(Say("System-Provided:")) + Expect(testUI.Out).To(Say("system-name: {")) + Expect(testUI.Out).To(Say(`"mysql": \[`)) + Expect(testUI.Out).To(Say(`"system-value"`)) + Expect(testUI.Out).To(Say(`\],`)) + Expect(testUI.Out).To(Say(`"password": "{{test<3"`)) + Expect(testUI.Out).To(Say("}")) + Expect(testUI.Out).To(Say(`application-name: "{{application-value"`)) + + Expect(testUI.Out).To(Say("User-Provided:")) + Expect(testUI.Out).To(Say(`user-name: {{user-value`)) + + Expect(testUI.Out).To(Say("Running Environment Variable Groups:")) + Expect(testUI.Out).To(Say(`running-name: {{running-value`)) + + Expect(testUI.Out).To(Say("Staging Environment Variable Groups:")) + Expect(testUI.Out).To(Say(`staging-name: {{staging-value`)) + }) + }) }) }) }) diff --git a/go.mod b/go.mod index c8432600d9e..66c59a32b7d 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module code.cloudfoundry.org/cli -go 1.22 +go 1.22.0 require ( code.cloudfoundry.org/bytefmt v0.0.0-20230612151507-41ef4d1f67a4 @@ -39,9 +39,9 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/tedsuo/rata v1.0.1-0.20170830210128-07d200713958 github.com/vito/go-interact v0.0.0-20171111012221-fa338ed9e9ec - golang.org/x/crypto v0.24.0 + golang.org/x/crypto v0.25.0 golang.org/x/net v0.26.0 - golang.org/x/term v0.21.0 + golang.org/x/term v0.22.0 golang.org/x/text v0.16.0 gopkg.in/cheggaaa/pb.v1 v1.0.28 gopkg.in/yaml.v2 v2.4.0 @@ -80,7 +80,7 @@ require ( golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.17.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.21.0 // indirect + golang.org/x/sys v0.22.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/appengine v1.6.8 // indirect diff --git a/go.sum b/go.sum index 0c245595c75..66c5226e2ba 100644 --- a/go.sum +++ b/go.sum @@ -261,8 +261,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -326,12 +326,12 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= -golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/util/ui/ui.go b/util/ui/ui.go index 54d7ea9bcaa..435dc4da50d 100644 --- a/util/ui/ui.go +++ b/util/ui/ui.go @@ -248,6 +248,15 @@ func (ui *UI) DisplayText(template string, templateValues ...map[string]interfac fmt.Fprintf(ui.Out, "%s\n", ui.TranslateText(template, templateValues...)) } +// DisplayTextLiteral outputs the text to ui.Out without modification. +// This function should only be used when no translation or templating is required. +func (ui *UI) DisplayTextLiteral(text string) { + ui.terminalLock.Lock() + defer ui.terminalLock.Unlock() + + fmt.Fprintf(ui.Out, "%s\n", text) +} + // DisplayTextWithBold translates the template, bolds the templateValues, // substitutes templateValues into the template, and outputs // the result to ui.Out. Only the first map in templateValues is used. diff --git a/util/ui/ui_test.go b/util/ui/ui_test.go index 256fb895426..67fb070dc82 100644 --- a/util/ui/ui_test.go +++ b/util/ui/ui_test.go @@ -186,6 +186,13 @@ var _ = Describe("UI", func() { }) }) + Describe("DisplayTextLiteral", func() { + It("displays the text into ui.Out with a newline", func() { + ui.DisplayTextLiteral("some text") + Expect(out).To(Say("some text\n")) + }) + }) + Describe("Display JSON", func() { It("displays the indented JSON object", func() { obj := map[string]interface{}{