Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package kubectl-view-secret for
openSUSE:Factory checked in at 2024-08-17 12:41:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/kubectl-view-secret (Old)
and /work/SRC/openSUSE:Factory/.kubectl-view-secret.new.2698 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kubectl-view-secret"
Sat Aug 17 12:41:42 2024 rev:4 rq:1194373 version:0.13.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/kubectl-view-secret/kubectl-view-secret.changes
2024-08-02 17:27:56.398795630 +0200
+++
/work/SRC/openSUSE:Factory/.kubectl-view-secret.new.2698/kubectl-view-secret.changes
2024-08-17 12:42:00.185404657 +0200
@@ -1,0 +2,9 @@
+Fri Aug 16 18:13:25 UTC 2024 - [email protected]
+
+- Update to version 0.13.0:
+ * Update changelog for v0.13.0 release
+ * Integrate with huh for better interface (#47)
+ * Add instructions for nixpkgs to README (#49)
+ * Add test coverage via codecov.io (#48)
+
+-------------------------------------------------------------------
@@ -4,2 +13,2 @@
-- make kubectl recognize this as a plugin by having an executable with the
- right name
+- make kubectl recognize this as a plugin by having an executable
+ with the right name
Old:
----
kubectl-view-secret-0.12.1.obscpio
New:
----
kubectl-view-secret-0.13.0.obscpio
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ kubectl-view-secret.spec ++++++
--- /var/tmp/diff_new_pack.YZuwSe/_old 2024-08-17 12:42:00.689425616 +0200
+++ /var/tmp/diff_new_pack.YZuwSe/_new 2024-08-17 12:42:00.693425782 +0200
@@ -23,7 +23,7 @@
%define executable_name kubectl-view_secret
Name: kubectl-view-secret
-Version: 0.12.1
+Version: 0.13.0
Release: 0
Summary: Kubernetes CLI plugin to decode Kubernetes secrets
License: MIT
++++++ _service ++++++
--- /var/tmp/diff_new_pack.YZuwSe/_old 2024-08-17 12:42:00.721426947 +0200
+++ /var/tmp/diff_new_pack.YZuwSe/_new 2024-08-17 12:42:00.725427113 +0200
@@ -3,7 +3,7 @@
<param name="url">https://github.com/elsesiy/kubectl-view-secret</param>
<param name="scm">git</param>
<param name="exclude">.git</param>
- <param name="revision">v0.12.1</param>
+ <param name="revision">v0.13.0</param>
<param name="versionformat">@PARENT_TAG@</param>
<param name="changesgenerate">enable</param>
<param name="versionrewrite-pattern">v(.*)</param>
++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.YZuwSe/_old 2024-08-17 12:42:00.745427945 +0200
+++ /var/tmp/diff_new_pack.YZuwSe/_new 2024-08-17 12:42:00.749428111 +0200
@@ -1,6 +1,6 @@
<servicedata>
<service name="tar_scm">
<param
name="url">https://github.com/elsesiy/kubectl-view-secret</param>
- <param
name="changesrevision">122b2e639fd48b6bd2655957e82c539d83ced5df</param></service></servicedata>
+ <param
name="changesrevision">9599a2e2e9bf4ecc14d6b4fb52230c10195ecb4e</param></service></servicedata>
(No newline at EOF)
++++++ kubectl-view-secret-0.12.1.obscpio -> kubectl-view-secret-0.13.0.obscpio
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/.github/workflows/ci.yml
new/kubectl-view-secret-0.13.0/.github/workflows/ci.yml
--- old/kubectl-view-secret-0.12.1/.github/workflows/ci.yml 2024-08-02
06:26:00.000000000 +0200
+++ new/kubectl-view-secret-0.13.0/.github/workflows/ci.yml 2024-08-14
22:05:48.000000000 +0200
@@ -1,15 +1,25 @@
---
name: ci
-on:
- pull_request:
+on: [push, pull_request]
jobs:
ci_job:
name: test
runs-on: ubuntu-22.04
- container:
- image: golang:1.22
steps:
- name: Checkout
uses: actions/checkout@v4
+ - name: Create kind cluster
+ uses: helm/kind-action@v1
+ with:
+ cluster_name: kvs-test
+ install_only: true
+ - name: Prepare env
+ run: make bootstrap
- name: Test
run: make test
+ - name: Generate coverage report
+ run: make test-cov
+ - name: Upload results to Codecov
+ uses: codecov/codecov-action@v4
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/.gitignore
new/kubectl-view-secret-0.13.0/.gitignore
--- old/kubectl-view-secret-0.12.1/.gitignore 2024-08-02 06:26:00.000000000
+0200
+++ new/kubectl-view-secret-0.13.0/.gitignore 2024-08-14 22:05:48.000000000
+0200
@@ -4,4 +4,5 @@
.idea
.vscode
-kubectl-view-secret
\ No newline at end of file
+kubectl-view-secret
+coverage.txt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/CHANGELOG.md
new/kubectl-view-secret-0.13.0/CHANGELOG.md
--- old/kubectl-view-secret-0.12.1/CHANGELOG.md 2024-08-02 06:26:00.000000000
+0200
+++ new/kubectl-view-secret-0.13.0/CHANGELOG.md 2024-08-14 22:05:48.000000000
+0200
@@ -1,8 +1,18 @@
# Changelog
-## [0.12.1](https://github.com/elsesiy/kubectl-view-secret/tree/0.12.1)
(2024-08-02)
+## [0.13.0](https://github.com/elsesiy/kubectl-view-secret/tree/0.13.0)
(2024-08-14)
-[Full
Changelog](https://github.com/elsesiy/kubectl-view-secret/compare/v0.12.0...0.12.1)
+[Full
Changelog](https://github.com/elsesiy/kubectl-view-secret/compare/v0.12.1...0.13.0)
+
+**Merged pull requests:**
+
+- Add instructions for nixpkgs to README
[\#49](https://github.com/elsesiy/kubectl-view-secret/pull/49)
([elsesiy](https://github.com/elsesiy))
+- Add test coverage via codecov.io
[\#48](https://github.com/elsesiy/kubectl-view-secret/pull/48)
([elsesiy](https://github.com/elsesiy))
+- Integrate with huh for better interface
[\#47](https://github.com/elsesiy/kubectl-view-secret/pull/47)
([elsesiy](https://github.com/elsesiy))
+
+## [v0.12.1](https://github.com/elsesiy/kubectl-view-secret/tree/v0.12.1)
(2024-08-02)
+
+[Full
Changelog](https://github.com/elsesiy/kubectl-view-secret/compare/v0.12.0...v0.12.1)
**Closed issues:**
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/Makefile
new/kubectl-view-secret-0.13.0/Makefile
--- old/kubectl-view-secret-0.12.1/Makefile 2024-08-02 06:26:00.000000000
+0200
+++ new/kubectl-view-secret-0.13.0/Makefile 2024-08-14 22:05:48.000000000
+0200
@@ -1,13 +1,22 @@
SOURCES := $(shell find . -name '*.go')
BINARY := kubectl-view-secret
+COV_REPORT := "coverage.txt"
build: kubectl-view-secret
+bootstrap:
+ ./hack/kind-bootstrap.sh
+
test: $(SOURCES)
go test -v -short -race -timeout 30s ./...
+test-cov:
+ go test ./... -coverprofile=$(COV_REPORT)
+ go tool cover -html=$(COV_REPORT)
+
clean:
@rm -rf $(BINARY)
+ @kind delete cluster --name kvs-test
$(BINARY): $(SOURCES)
CGO_ENABLED=0 go build -o $(BINARY) -ldflags="-s -w" ./cmd/$(BINARY).go
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/README.md
new/kubectl-view-secret-0.13.0/README.md
--- old/kubectl-view-secret-0.12.1/README.md 2024-08-02 06:26:00.000000000
+0200
+++ new/kubectl-view-secret-0.13.0/README.md 2024-08-14 22:05:48.000000000
+0200
@@ -2,9 +2,12 @@
[](https://goreportcard.com/report/github.com/elsesiy/kubectl-view-secret)

+[](https://codecov.io/github/elsesiy/kubectl-view-secret)
[](http://twitter.com/elsesiy)
[](https://github.com/elsesiy/kubectl-view-secret/releases)
+
+
This plugin allows for easy secret decoding. Useful if you want to see what's
inside of a secret without always go through the following:
1. `kubectl get secret <secret> -o yaml`
@@ -58,6 +61,13 @@
Contribution by [@jocelynthode](https://github.com/jocelynthode)
+#### Nix
+You can install the latest version from Nixpkgs
([24.05](https://search.nixos.org/packages?channel=24.05&from=0&size=50&sort=relevance&type=packages&query=kubectl-view-secret),
[unstable](https://search.nixos.org/packages?channel=unstable&show=kubectl-view-secret&from=0&size=50&sort=relevance&type=packages&query=kubectl-view-secret))
or try it via a temporary nix-shell:
+
+```
+nix-shell -p kubectl-view-secret
+```
+
### Build from source
# Clone this repository (or your fork)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/go.mod
new/kubectl-view-secret-0.13.0/go.mod
--- old/kubectl-view-secret-0.12.1/go.mod 2024-08-02 06:26:00.000000000
+0200
+++ new/kubectl-view-secret-0.13.0/go.mod 2024-08-14 22:05:48.000000000
+0200
@@ -3,12 +3,43 @@
go 1.22
require (
+ github.com/charmbracelet/bubbletea v0.26.6
+ github.com/charmbracelet/huh v0.5.2
github.com/goccy/go-json v0.10.3
- github.com/magiconair/properties v1.8.7
github.com/spf13/cobra v1.8.1
+ github.com/stretchr/testify v1.9.0
)
require (
+ github.com/atotto/clipboard v0.1.4 // indirect
+ github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
+ github.com/catppuccin/go v0.2.0 // indirect
+ github.com/charmbracelet/bubbles v0.18.0 // indirect
+ github.com/charmbracelet/lipgloss v0.12.1 // indirect
+ github.com/charmbracelet/x/ansi v0.1.4 // indirect
+ github.com/charmbracelet/x/exp/strings
v0.0.0-20240806224806-c5da01e9b4d1 // indirect
+ github.com/charmbracelet/x/exp/term v0.0.0-20240725160154-f9f6568126ec
// indirect
+ github.com/charmbracelet/x/input v0.1.3 // indirect
+ github.com/charmbracelet/x/term v0.1.1 // indirect
+ github.com/charmbracelet/x/windows v0.1.2 // indirect
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/dustin/go-humanize v1.0.1 // indirect
+ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f //
indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
+ github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/mattn/go-localereader v0.0.1 // indirect
+ github.com/mattn/go-runewidth v0.0.16 // indirect
+ github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
+ github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
+ github.com/muesli/cancelreader v0.2.2 // indirect
+ github.com/muesli/termenv v0.15.2 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/rivo/uniseg v0.4.7 // indirect
github.com/spf13/pflag v1.0.5 // indirect
+ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
+ golang.org/x/sync v0.8.0 // indirect
+ golang.org/x/sys v0.23.0 // indirect
+ golang.org/x/text v0.17.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/go.sum
new/kubectl-view-secret-0.13.0/go.sum
--- old/kubectl-view-secret-0.12.1/go.sum 2024-08-02 06:26:00.000000000
+0200
+++ new/kubectl-view-secret-0.13.0/go.sum 2024-08-14 22:05:48.000000000
+0200
@@ -1,19 +1,81 @@
-github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod
h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/atotto/clipboard v0.1.4
h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
+github.com/atotto/clipboard v0.1.4/go.mod
h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1
h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod
h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
+github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA=
+github.com/catppuccin/go v0.2.0/go.mod
h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
+github.com/charmbracelet/bubbles v0.18.0
h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0=
+github.com/charmbracelet/bubbles v0.18.0/go.mod
h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw=
+github.com/charmbracelet/bubbletea v0.26.6
h1:zTCWSuST+3yZYZnVSvbXwKOPRSNZceVeqpzOLN2zq1s=
+github.com/charmbracelet/bubbletea v0.26.6/go.mod
h1:dz8CWPlfCCGLFbBlTY4N7bjLiyOGDJEnd2Muu7pOWhk=
+github.com/charmbracelet/huh v0.5.2
h1:ofeNkJ4iaFnzv46Njhx896DzLUe/j0L2QAf8znwzX4c=
+github.com/charmbracelet/huh v0.5.2/go.mod
h1:Sf7dY0oAn6N/e3sXJFtFX9hdQLrUdO3z7AYollG9bAM=
+github.com/charmbracelet/lipgloss v0.12.1
h1:/gmzszl+pedQpjCOH+wFkZr/N90Snz40J/NR7A0zQcs=
+github.com/charmbracelet/lipgloss v0.12.1/go.mod
h1:V2CiwIuhx9S1S1ZlADfOj9HmxeMAORuz5izHb0zGbB8=
+github.com/charmbracelet/x/ansi v0.1.4
h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM=
+github.com/charmbracelet/x/ansi v0.1.4/go.mod
h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
+github.com/charmbracelet/x/exp/strings v0.0.0-20240806224806-c5da01e9b4d1
h1:KuM2G5oWPAd0FlLh+mSl5p6bLVKK52KEmSik5z6UNbE=
+github.com/charmbracelet/x/exp/strings
v0.0.0-20240806224806-c5da01e9b4d1/go.mod
h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
+github.com/charmbracelet/x/exp/term v0.0.0-20240725160154-f9f6568126ec
h1:tg3MAnVjISHLuysTCGGtsjkuoBzPzL9OrWvxs5Rd29I=
+github.com/charmbracelet/x/exp/term v0.0.0-20240725160154-f9f6568126ec/go.mod
h1:YG0dzr31td4jqC86wFlB8fJGgPwqPgTSa8VC0Hf7u+k=
+github.com/charmbracelet/x/input v0.1.3
h1:oy4TMhyGQsYs/WWJwu1ELUMFnjiUAXwtDf048fHbCkg=
+github.com/charmbracelet/x/input v0.1.3/go.mod
h1:1gaCOyw1KI9e2j00j/BBZ4ErzRZqa05w0Ghn83yIhKU=
+github.com/charmbracelet/x/term v0.1.1
h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI=
+github.com/charmbracelet/x/term v0.1.1/go.mod
h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw=
+github.com/charmbracelet/x/windows v0.1.2
h1:Iumiwq2G+BRmgoayww/qfcvof7W/3uLoelhxojXlRWg=
+github.com/charmbracelet/x/windows v0.1.2/go.mod
h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod
h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
-github.com/goccy/go-json v0.10.2
h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
-github.com/goccy/go-json v0.10.2/go.mod
h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/davecgh/go-spew v1.1.1
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dustin/go-humanize v1.0.1
h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
+github.com/dustin/go-humanize v1.0.1/go.mod
h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
+github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f
h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
+github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod
h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
github.com/goccy/go-json v0.10.3
h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod
h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/inconshreveable/mousetrap v1.1.0
h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod
h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/magiconair/properties v1.8.7
h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
-github.com/magiconair/properties v1.8.7/go.mod
h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
+github.com/lucasb-eyer/go-colorful v1.2.0
h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
+github.com/lucasb-eyer/go-colorful v1.2.0/go.mod
h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/mattn/go-isatty v0.0.20
h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod
h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-localereader v0.0.1
h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
+github.com/mattn/go-localereader v0.0.1/go.mod
h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
+github.com/mattn/go-runewidth v0.0.16
h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
+github.com/mattn/go-runewidth v0.0.16/go.mod
h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mitchellh/hashstructure/v2 v2.0.2
h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
+github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod
h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
+github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6
h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
+github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod
h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
+github.com/muesli/cancelreader v0.2.2
h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
+github.com/muesli/cancelreader v0.2.2/go.mod
h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
+github.com/muesli/termenv v0.15.2
h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
+github.com/muesli/termenv v0.15.2/go.mod
h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
+github.com/pmezard/go-difflib v1.0.0
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rivo/uniseg v0.2.0/go.mod
h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod
h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/russross/blackfriday/v2 v2.1.0/go.mod
h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
-github.com/spf13/cobra v1.8.0/go.mod
h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod
h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod
h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stretchr/testify v1.9.0
h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod
h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e
h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod
h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
+golang.org/x/exp v0.0.0-20231006140011-7918f672742d
h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
+golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod
h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
+golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
+golang.org/x/text v0.17.0/go.mod
h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/hack/kind-bootstrap.sh
new/kubectl-view-secret-0.13.0/hack/kind-bootstrap.sh
--- old/kubectl-view-secret-0.12.1/hack/kind-bootstrap.sh 1970-01-01
01:00:00.000000000 +0100
+++ new/kubectl-view-secret-0.13.0/hack/kind-bootstrap.sh 2024-08-14
22:05:48.000000000 +0200
@@ -0,0 +1,70 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+CLUSTER_NAME="kvs-test"
+
+# Check if kind & kubectl are installed
+which kind &>/dev/null || { echo "failed to find 'kind' binary, please install
it" && exit 1; }
+which kubectl &>/dev/null || { echo "failed to find 'kubectl' binary, please
install it" && exit 1; }
+
+# Ensure the cluster exists
+[[ $(kind get clusters) == *$CLUSTER_NAME* ]] || kind create cluster --name
$CLUSTER_NAME
+
+# Set context in case there are mulitple
+kubectl config set-context kind-${CLUSTER_NAME}
+
+# Seed test secrets
+
+## secret 'test' in namespace 'default' (multiple keys)
+kubectl apply -f - <<EOF
+apiVersion: v1
+data:
+ key1: dmFsdWUxCg==
+ key2: dmFsdWUyCg==
+kind: Secret
+metadata:
+ name: test
+ namespace: default
+type: Opaque
+EOF
+
+## secret 'test2' in namespace 'default' (single key)
+kubectl apply -f - <<EOF
+apiVersion: v1
+data:
+ key1: dmFsdWUx
+kind: Secret
+metadata:
+ name: test2
+ namespace: default
+type: Opaque
+EOF
+
+## 'another' namespace
+kubectl apply -f - <<EOF
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: another
+EOF
+
+## secret 'gopher' in namespace 'another' (single key)
+kubectl apply -f - <<EOF
+apiVersion: v1
+data:
+ foo: YmFy
+kind: Secret
+metadata:
+ name: gopher
+ namespace: another
+type: Opaque
+EOF
+
+## 'empty' namespace
+kubectl apply -f - <<EOF
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: empty
+EOF
Binary files old/kubectl-view-secret-0.12.1/media/view-secret.gif and
new/kubectl-view-secret-0.13.0/media/view-secret.gif differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/media/view-secret.tape
new/kubectl-view-secret-0.13.0/media/view-secret.tape
--- old/kubectl-view-secret-0.12.1/media/view-secret.tape 1970-01-01
01:00:00.000000000 +0100
+++ new/kubectl-view-secret-0.13.0/media/view-secret.tape 2024-08-14
22:05:48.000000000 +0200
@@ -0,0 +1,88 @@
+Output media/view-secret.gif
+Set Theme "Catppuccin Mocha"
+Set CursorBlink false
+Set Width 1400
+
+Hide
+Type "# Secrets in current namespace"
+Enter 2
+Show
+Sleep 2
+Type "kubectl get secret"
+Enter
+Sleep 2
+Type "clear"
+Enter
+
+Hide
+Type "# Showing all secrets in current namespace with interactive selection"
+Enter 2
+Show
+Sleep 2
+Type "kubectl view-secret"
+Enter
+Sleep 2
+Down
+Sleep 1
+Enter
+Sleep 1
+Type "clear"
+Enter
+
+Hide
+Type "# View 'test' secret in current namespace with interactive selection for
a single key"
+Enter 2
+Show
+Sleep 2
+Type "kubectl view-secret test"
+Enter
+Sleep 1
+Type "/key2"
+Sleep 1
+Enter
+Sleep 1
+Type "clear"
+Enter
+
+Hide
+Type "# View 'test' secret in current namespace and show all keys"
+Enter 2
+Show
+Sleep 2
+Type "kubectl view-secret test -a"
+Enter
+Sleep 1
+Type "clear"
+Enter
+
+Hide
+Type "# View 'test2' secret in current namespace immediately shows the secret
contents (only one key exists)"
+Enter 2
+Show
+Sleep 2
+Type "kubectl view-secret test2"
+Enter
+Sleep 1
+Type "clear"
+Enter
+
+Hide
+Type "# Secrets in 'another' namespace"
+Enter 2
+Show
+Sleep 2
+Type "kubectl get secret -n another"
+Enter
+Sleep 2
+Type "clear"
+Enter
+
+Hide
+Type "# View 'gopher' secret in 'another' namespace and silence info about
single key"
+Enter 2
+Show
+Sleep 2
+Type "kubectl view-secret gopher -n another -q"
+Enter
+
+Sleep 5
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/pkg/cmd/types.go
new/kubectl-view-secret-0.13.0/pkg/cmd/types.go
--- old/kubectl-view-secret-0.12.1/pkg/cmd/types.go 1970-01-01
01:00:00.000000000 +0100
+++ new/kubectl-view-secret-0.13.0/pkg/cmd/types.go 2024-08-14
22:05:48.000000000 +0200
@@ -0,0 +1,17 @@
+package cmd
+
+type SecretList struct {
+ Items []Secret `json:"items"`
+}
+
+type Secret struct {
+ Data SecretData `json:"data"`
+ Metadata Metadata `json:"metadata"`
+}
+
+type SecretData map[string]string
+
+type Metadata struct {
+ Name string `json:"name"`
+ Namespace string `json:"namespace"`
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/pkg/cmd/types_test.go
new/kubectl-view-secret-0.13.0/pkg/cmd/types_test.go
--- old/kubectl-view-secret-0.12.1/pkg/cmd/types_test.go 1970-01-01
01:00:00.000000000 +0100
+++ new/kubectl-view-secret-0.13.0/pkg/cmd/types_test.go 2024-08-14
22:05:48.000000000 +0200
@@ -0,0 +1,96 @@
+package cmd
+
+import (
+ "encoding/json"
+ "errors"
+ "reflect"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+var (
+ validSecretJson = `{
+ "apiVersion": "v1",
+ "data": {
+ "key1": "dmFsdWUxCg==",
+ "key2": "dmFsdWUyCg=="
+ },
+ "kind": "Secret",
+ "metadata": {
+ "creationTimestamp": "2024-08-02T21:25:40Z",
+ "name": "test",
+ "namespace": "default",
+ "resourceVersion": "715",
+ "uid": "0027fdc9-5371-4715-a0a8-61f3f78fdd36"
+ },
+ "type": "Opaque"
+}`
+
+ emptySecretJson = `{
+ "apiVersion": "v1",
+ "data": {},
+ "kind": "Secret",
+ "metadata": {
+ "name": "test-empty",
+ "namespace": "default",
+ },
+ "type": "Opaque"
+}`
+)
+
+func TestSerialize(t *testing.T) {
+ tests := map[string]struct {
+ input string
+ want Secret
+ wantErr error
+ }{
+ "empty secret": {
+ input: emptySecretJson,
+ want: Secret{
+ Metadata: Metadata{
+ Name: "test",
+ Namespace: "default",
+ },
+ },
+ wantErr: errors.New("invalid character '}' looking for
beginning of object key string"),
+ },
+ "valid secret": {
+ input: validSecretJson,
+ want: Secret{
+ Data: SecretData{
+ "key1": "dmFsdWUxCg==",
+ "key2": "dmFsdWUyCg==",
+ },
+ Metadata: Metadata{
+ Name: "test",
+ Namespace: "default",
+ },
+ },
+ },
+ }
+
+ for name, tt := range tests {
+ t.Run(name, func(t *testing.T) {
+ t.Parallel()
+
+ var got Secret
+ err := json.Unmarshal([]byte(tt.input), &got)
+ if err != nil {
+ if tt.wantErr == nil {
+ assert.Fail(t, "unexpected error", err)
+ } else if err.Error() != tt.wantErr.Error() {
+ assert.Equal(t, tt.wantErr, err)
+ }
+ return
+ } else if tt.wantErr != nil {
+ assert.Fail(t, "expected error, got nil",
tt.wantErr)
+ return
+ }
+
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Fatal(err)
+ }
+ })
+ }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/kubectl-view-secret-0.12.1/pkg/cmd/view-secret.go
new/kubectl-view-secret-0.13.0/pkg/cmd/view-secret.go
--- old/kubectl-view-secret-0.12.1/pkg/cmd/view-secret.go 2024-08-02
06:26:00.000000000 +0200
+++ new/kubectl-view-secret-0.13.0/pkg/cmd/view-secret.go 2024-08-14
22:05:48.000000000 +0200
@@ -11,6 +11,8 @@
"sort"
"strings"
+ tea "github.com/charmbracelet/bubbletea"
+ "github.com/charmbracelet/huh"
"github.com/goccy/go-json"
"github.com/spf13/cobra"
)
@@ -39,19 +41,23 @@
%[1]s view-secret <secret> -q/--quiet
`
- singleKeyDescription = "Choosing key: %[1]s"
- listDescription = "Multiple sub keys found. Specify another
argument, one of:"
- listPrefix = "->"
+ secretDescription = "Found %d keys in secret %q. Choose one or
select 'all' to view."
+ secretListDescription = "Found %d secrets. Choose one."
+ secretListTitle = "Available Secrets"
+ secretTitle = "Secret Data"
+ singleKeyDescription = "Viewing only available key: %[1]s"
)
-// ErrSecretKeyNotFound is thrown if the key doesn't exist in the secret
-var ErrSecretKeyNotFound = errors.New("provided key not found in secret")
+var (
+ // ErrNoSecretFound is thrown when no secret name was provided but we
didn't find any secrets
+ ErrNoSecretFound = errors.New("no secrets found")
-// ErrSecretEmpty is thrown when there's no data in the secret
-var ErrSecretEmpty = errors.New("secret is empty")
+ // ErrSecretEmpty is thrown when there's no data in the secret
+ ErrSecretEmpty = errors.New("secret is empty")
-// ErrInsufficientArgs is thrown if arg len <1 or >2
-var ErrInsufficientArgs = fmt.Errorf("\nincorrect number or arguments, see
--help for usage instructions")
+ // ErrSecretKeyNotFound is thrown if the key doesn't exist in the secret
+ ErrSecretKeyNotFound = errors.New("provided key not found in secret")
+)
// CommandOpts is the struct holding common properties
type CommandOpts struct {
@@ -71,14 +77,13 @@
res := &CommandOpts{}
cmd := &cobra.Command{
- Use: "view-secret [secret-name] [secret-key]",
- Short: "Decode a kubernetes secret by name & key in the
current context/cluster/namespace",
+ Args: cobra.RangeArgs(0, 2),
Example: fmt.Sprintf(example, "kubectl"),
+ Short: "Decode a kubernetes secret by name & key in the
current context/cluster/namespace",
SilenceUsage: true,
+ Use: "view-secret [secret-name] [secret-key]",
RunE: func(c *cobra.Command, args []string) error {
- if err := res.Validate(args); err != nil {
- return err
- }
+ res.ParseArgs(args)
if err := res.Retrieve(c); err != nil {
return err
}
@@ -100,19 +105,16 @@
return cmd
}
-// Validate ensures proper command usage
-func (c *CommandOpts) Validate(args []string) error {
+// ParseArgs serializes the user supplied program arguments
+func (c *CommandOpts) ParseArgs(args []string) {
argLen := len(args)
- if argLen < 1 || argLen > 2 {
- return ErrInsufficientArgs
- }
+ if argLen >= 1 {
+ c.secretName = args[0]
- c.secretName = args[0]
- if argLen == 2 {
- c.secretKey = args[1]
+ if argLen == 2 {
+ c.secretKey = args[1]
+ }
}
-
- return nil
}
// Retrieve reads the kubeconfig and decodes the secret
@@ -124,7 +126,12 @@
impersonateGroupOverride, _ := cmd.Flags().GetString("as-group")
var res, cmdErr bytes.Buffer
- commandArgs := []string{"get", "secret", c.secretName, "-o", "json"}
+
+ commandArgs := []string{"get", "secret", "-o", "json"}
+ if c.secretName != "" {
+ commandArgs = []string{"get", "secret", c.secretName, "-o",
"json"}
+ }
+
if nsOverride != "" {
commandArgs = append(commandArgs, "-n", nsOverride)
}
@@ -154,54 +161,108 @@
return nil
}
- var secret map[string]interface{}
- if err := json.Unmarshal(res.Bytes(), &secret); err != nil {
- return err
+ var secret Secret
+ if c.secretName == "" {
+ var secretList SecretList
+ if err := json.Unmarshal(res.Bytes(), &secretList); err != nil {
+ return err
+ }
+
+ // Since we don't query valid namespaces, we'll avoid prompting
the user to select a secret if we didn't retrieve any secrets
+ if len(secretList.Items) == 0 {
+ return ErrNoSecretFound
+ }
+
+ opts := []string{}
+ secretMap := map[string]Secret{}
+ for _, v := range secretList.Items {
+ opts = append(opts, v.Metadata.Name)
+ secretMap[v.Metadata.Name] = v
+ }
+
+ err := huh.NewForm(
+ huh.NewGroup(
+ huh.NewSelect[string]().
+ Title(secretListTitle).
+
Description(fmt.Sprintf(secretListDescription, len(secretList.Items))).
+ Options(huh.NewOptions(opts...)...).
+ Value(&c.secretName),
+ ),
+ ).WithProgramOptions(tea.WithInput(cmd.InOrStdin()),
tea.WithOutput(cmd.OutOrStdout())).Run()
+ if err != nil {
+ return err
+ }
+
+ secret = secretMap[c.secretName]
+ } else {
+ if err := json.Unmarshal(res.Bytes(), &secret); err != nil {
+ return err
+ }
}
if c.quiet {
- return ProcessSecret(os.Stdout, io.Discard, secret,
c.secretKey, c.decodeAll)
+ return ProcessSecret(cmd.OutOrStdout(), io.Discard,
cmd.InOrStdin(), secret, c.secretKey, c.decodeAll)
}
- return ProcessSecret(os.Stdout, os.Stderr, secret, c.secretKey,
c.decodeAll)
+ return ProcessSecret(cmd.OutOrStdout(), cmd.OutOrStderr(),
cmd.InOrStdin(), secret, c.secretKey, c.decodeAll)
}
// ProcessSecret takes the secret and user input to determine the output
-func ProcessSecret(outWriter, errWriter io.Writer, secret
map[string]interface{}, secretKey string, decodeAll bool) error {
- data, ok := secret["data"].(map[string]interface{})
- if !ok {
+func ProcessSecret(outWriter, errWriter io.Writer, inputReader io.Reader,
secret Secret, secretKey string, decodeAll bool) error {
+ data := secret.Data
+ if len(data) == 0 {
return ErrSecretEmpty
}
var keys []string
- for k := range data {
+ for k := range secret.Data {
keys = append(keys, k)
}
sort.Strings(keys)
if decodeAll {
for _, k := range keys {
- b64d, _ :=
base64.StdEncoding.DecodeString(data[k].(string))
+ b64d, _ := base64.StdEncoding.DecodeString(data[k])
_, _ = fmt.Fprintf(outWriter, "%s='%s'\n", k,
strings.TrimSpace(string(b64d)))
}
} else if len(data) == 1 {
for k, v := range data {
_, _ = fmt.Fprintf(errWriter,
singleKeyDescription+"\n", k)
- b64d, _ := base64.StdEncoding.DecodeString(v.(string))
- _, _ = fmt.Fprint(outWriter, string(b64d))
+ b64d, _ := base64.StdEncoding.DecodeString(v)
+ _, _ = fmt.Fprintf(outWriter, "%s\n",
strings.TrimSpace(string(b64d)))
}
} else if secretKey != "" {
if v, ok := data[secretKey]; ok {
- b64d, _ := base64.StdEncoding.DecodeString(v.(string))
- _, _ = fmt.Fprint(outWriter, string(b64d))
+ b64d, _ := base64.StdEncoding.DecodeString(v)
+ _, _ = fmt.Fprintf(outWriter, "%s\n",
strings.TrimSpace(string(b64d)))
} else {
return ErrSecretKeyNotFound
}
} else {
- _, _ = fmt.Fprintln(errWriter, listDescription)
+ opts := []string{"all"}
for k := range data {
- _, _ = fmt.Fprintf(outWriter, "%s %s\n", listPrefix, k)
+ opts = append(opts, k)
+ }
+
+ var selection string
+ err := huh.NewForm(
+ huh.NewGroup(
+ huh.NewSelect[string]().
+ Title(secretTitle).
+
Description(fmt.Sprintf(secretDescription, len(data), secret.Metadata.Name)).
+ Options(huh.NewOptions(opts...)...).
+ Value(&selection),
+ ),
+ ).WithProgramOptions(tea.WithInput(inputReader),
tea.WithOutput(outWriter)).Run()
+ if err != nil {
+ return err
}
+
+ if selection == "all" {
+ decodeAll = true
+ }
+
+ return ProcessSecret(outWriter, errWriter, inputReader, secret,
selection, decodeAll)
}
return nil
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/kubectl-view-secret-0.12.1/pkg/cmd/view-secret_test.go
new/kubectl-view-secret-0.13.0/pkg/cmd/view-secret_test.go
--- old/kubectl-view-secret-0.12.1/pkg/cmd/view-secret_test.go 2024-08-02
06:26:00.000000000 +0200
+++ new/kubectl-view-secret-0.13.0/pkg/cmd/view-secret_test.go 2024-08-14
22:05:48.000000000 +0200
@@ -1,81 +1,135 @@
package cmd
import (
- "bufio"
"bytes"
+ "errors"
"fmt"
- "reflect"
- "sort"
+ "io"
"strings"
"testing"
- "github.com/goccy/go-json"
- "github.com/magiconair/properties/assert"
+ "github.com/stretchr/testify/assert"
)
-const (
- testSecret = `
-{
- "data": {
- "TEST_CONN_STR":
"bW9uZ29kYjovL215REJSZWFkZXI6RDFmZmljdWx0UCU0MHNzdzByZEBtb25nb2RiMC5leGFtcGxlLmNvbToyNzAxNy8/YXV0aFNvdXJjZT1hZG1pbg==",
- "TEST_PASSWORD": "c2VjcmV0Cg==",
- "TEST_PASSWORD_2": "dmVyeXNlY3JldAo="
- }
-}
-`
- testSecretSingle = `
-{
- "data": {
- "SINGLE_PASSWORD": "c2VjcmV0Cg=="
- }
-}
-`
- testSecretEmpty = "{}"
+var (
+ secret = SecretData{
+ "TEST_CONN_STR":
"bW9uZ29kYjovL215REJSZWFkZXI6RDFmZmljdWx0UCU0MHNzdzByZEBtb25nb2RiMC5leGFtcGxlLmNvbToyNzAxNy8/YXV0aFNvdXJjZT1hZG1pbg==",
+ "TEST_PASSWORD": "c2VjcmV0Cg==",
+ "TEST_PASSWORD_2": "dmVyeXNlY3JldAo=",
+ }
+
+ secretSingle = SecretData{
+ "SINGLE_PASSWORD": "c2VjcmV0Cg==",
+ }
+
+ secretEmpty = SecretData{}
)
-func TestValidate(t *testing.T) {
+func TestParseArgs(t *testing.T) {
opts := CommandOpts{}
tests := map[string]struct {
- opts CommandOpts
- args []string
- err error
+ opts CommandOpts
+ args []string
+ wantOpts CommandOpts
}{
- "args insufficient length": {opts, []string{},
ErrInsufficientArgs},
- "valid args": {opts, []string{"test", "key"},
nil},
+ "one arg": {opts, []string{"test"}, CommandOpts{secretName:
"test"}},
+ "two args": {opts, []string{"test", "key"},
CommandOpts{secretName: "test", secretKey: "key"}},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
- got := test.opts.Validate(test.args)
- want := test.err
- if got != want {
- t.Errorf("got %v, want %v", got, want)
+ t.Parallel()
+
+ test.opts.ParseArgs(test.args)
+ got := test.opts
+ if got != test.wantOpts {
+ t.Errorf("got %v, want %v", got, test.wantOpts)
}
})
}
}
-func TestProcessSecret(t *testing.T) {
- var secret, secretSingle, secretEmpty map[string]interface{}
- _ = json.Unmarshal([]byte(testSecret), &secret)
- _ = json.Unmarshal([]byte(testSecretSingle), &secretSingle)
- _ = json.Unmarshal([]byte(testSecretEmpty), &secretEmpty)
+func TestNewCmdViewSecret(t *testing.T) {
+ tests := map[string]struct {
+ args []string
+ feedkeys string
+ want string
+ wantErr error
+ }{
+ "all": {args: []string{"test", "--all"},
want: `key1='value1'\nkey2='value2'`},
+ "custom ctx": {args: []string{"test",
"--context", "gotest"}},
+ "custom kubecfg": {args: []string{"test",
"--kubeconfig", "cfg"}},
+ "custom ns (does not exist)": {args: []string{"test",
"--namespace", "bob"}, want: `Error from server (NotFound): namespaces "bob"
not found`},
+ "custom ns (no secret)": {args: []string{"test",
"--namespace", "another"}, want: `Error from server (NotFound): secrets "test"
not found`},
+ "custom ns (valid secret)": {args: []string{"gopher",
"--namespace", "another"}, want: `Viewing only available key: foo\nbar`},
+ "impersonate group": {args: []string{"test", "--as",
"gopher"}},
+ "impersonate user & group": {args: []string{"test", "--as",
"gopher", "--as-group", "golovers"}},
+ // make bootstrap sources 2 test secrets in the default
namespace, select the first one and print all values
+ "interactive": {args: []string{"--all"},
feedkeys: "\r", want: `key1='value1'\nkey2='value2'`},
+ "interactive custom ns (no secret)": {args:
[]string{"--namespace", "empty"}, wantErr: ErrNoSecretFound},
+ "invalid arg count": {args: []string{"a", "b",
"c"}, wantErr: errors.New("accepts between 0 and 2 arg(s), received 3")},
+ "quiet": {args: []string{"test2",
"--quiet"}, want: `value1`},
+ "unknown flag": {args:
[]string{"--version"}, wantErr: errors.New("unknown flag: --version")},
+ }
+
+ for name, tt := range tests {
+ t.Run(name, func(t *testing.T) {
+ t.Parallel()
+
+ cmd := NewCmdViewSecret()
+ outBuf := bytes.NewBufferString("")
+ readBuf := &strings.Reader{}
+ if tt.feedkeys != "" {
+ readBuf = strings.NewReader(tt.feedkeys)
+ }
+ cmd.SetOut(outBuf)
+ cmd.SetIn(readBuf)
+ cmd.SetArgs(tt.args)
+
+ err := cmd.Execute()
+ if err != nil {
+ if tt.wantErr == nil {
+ assert.Fail(t, "unexpected error", err)
+ } else if err.Error() != tt.wantErr.Error() {
+ assert.Equal(t, tt.wantErr, err)
+ }
+ return
+ } else if tt.wantErr != nil {
+ assert.Fail(t, "expected error, got nil",
tt.wantErr)
+ return
+ }
+
+ _, err = io.ReadAll(outBuf)
+ if err != nil {
+ t.Fatal(err)
+ }
+ })
+ }
+}
+
+func TestProcessSecret(t *testing.T) {
tests := map[string]struct {
- secretData map[string]interface{}
+ secretData SecretData
wantStdOut []string
wantStdErr []string
secretKey string
decodeAll bool
err error
+ feedkeys string
}{
"view-secret <secret>": {
secret,
- []string{"-> TEST_CONN_STR", "-> TEST_PASSWORD", "->
TEST_PASSWORD_2"},
- []string{listDescription},
+ []string{
+
"TEST_CONN_STR='mongodb://myDBReader:d1fficultp%[email protected]:27017/?authSource=admin'",
+ "TEST_PASSWORD='secret'",
+ "TEST_PASSWORD_2='verysecret'",
+ },
+ []string{},
"",
false,
nil,
+ "\r", // selects 'all' as it's the default selection
},
"view-secret <secret-single-key>": {
secretSingle,
@@ -84,8 +138,9 @@
"",
false,
nil,
+ "",
},
- "view-secret test TEST_PASSWORD": {secret, []string{"secret"},
nil, "TEST_PASSWORD", false, nil},
+ "view-secret test TEST_PASSWORD": {secret, []string{"secret"},
nil, "TEST_PASSWORD", false, nil, ""},
"view-secret test -a": {
secret,
[]string{
@@ -97,40 +152,42 @@
"",
true,
nil,
+ "",
},
- "view-secret test NONE": {secret, nil, nil, "NONE", false,
ErrSecretKeyNotFound},
- "view-secret <secret-empty>": {secretEmpty, nil, nil, "",
false, ErrSecretEmpty},
+ "view-secret test NONE": {secret, nil, nil, "NONE", false,
ErrSecretKeyNotFound, ""},
+ "view-secret <secret-empty>": {secretEmpty, nil, nil, "",
false, ErrSecretEmpty, ""},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
- gotStdOut := bytes.Buffer{}
- gotStdErr := bytes.Buffer{}
- err := ProcessSecret(&gotStdOut, &gotStdErr,
test.secretData, test.secretKey, test.decodeAll)
+ t.Parallel()
+
+ stdOutBuf := bytes.Buffer{}
+ stdErrBuf := bytes.Buffer{}
+ readBuf := strings.Reader{}
+
+ if test.feedkeys != "" {
+ readBuf = *strings.NewReader(test.feedkeys)
+ }
+
+ err := ProcessSecret(&stdOutBuf, &stdErrBuf, &readBuf,
Secret{Data: test.secretData}, test.secretKey, test.decodeAll)
if test.err != nil {
assert.Equal(t, err, test.err)
} else {
- var gotStdOutArr, gotStdErrArr []string
- scanner :=
bufio.NewScanner(strings.NewReader(gotStdOut.String()))
- for scanner.Scan() {
- gotStdOutArr = append(gotStdOutArr,
scanner.Text())
- }
-
- scanner =
bufio.NewScanner(strings.NewReader(gotStdErr.String()))
- for scanner.Scan() {
- gotStdErrArr = append(gotStdErrArr,
scanner.Text())
- }
-
- sort.Strings(gotStdOutArr)
- sort.Strings(gotStdErrArr)
+ gotStdOut := stdOutBuf.String()
+ gotStdErr := stdErrBuf.String()
- if !reflect.DeepEqual(gotStdOutArr,
test.wantStdOut) {
- t.Errorf("got %v, want %v",
gotStdOutArr, test.wantStdOut)
+ for _, s := range test.wantStdOut {
+ if !assert.Contains(t, gotStdOut, s) {
+ t.Errorf("got %v, want %v",
gotStdOut, s)
+ }
}
- if !reflect.DeepEqual(gotStdErrArr,
test.wantStdErr) {
- t.Errorf("got %v, want %v",
gotStdErrArr, test.wantStdErr)
+ for _, s := range test.wantStdErr {
+ if !assert.Contains(t, gotStdErr, s) {
+ t.Errorf("got %v, want %v",
gotStdErr, s)
+ }
}
}
})
++++++ kubectl-view-secret.obsinfo ++++++
--- /var/tmp/diff_new_pack.YZuwSe/_old 2024-08-17 12:42:00.861432768 +0200
+++ /var/tmp/diff_new_pack.YZuwSe/_new 2024-08-17 12:42:00.865432935 +0200
@@ -1,5 +1,5 @@
name: kubectl-view-secret
-version: 0.12.1
-mtime: 1722572760
-commit: 122b2e639fd48b6bd2655957e82c539d83ced5df
+version: 0.13.0
+mtime: 1723665948
+commit: 9599a2e2e9bf4ecc14d6b4fb52230c10195ecb4e
++++++ vendor.tar.gz ++++++
++++ 302658 lines of diff (skipped)