diff --git a/.chglog/config.yml b/.chglog/config.yml index 53f57de..89c7a0a 100644 --- a/.chglog/config.yml +++ b/.chglog/config.yml @@ -5,18 +5,18 @@ info: repository_url: https://github.com/Bornholm/formidable options: commits: - # filters: - # Type: - # - feat - # - fix - # - perf - # - refactor + filters: + Type: + - feat + - fix + - perf + - refactor commit_groups: - # title_maps: - # feat: Features - # fix: Bug Fixes - # perf: Performance Improvements - # refactor: Code Refactoring + title_maps: + feat: Features + fix: Bug Fixes + perf: Performance Improvements + refactor: Code Refactoring header: pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$" pattern_maps: diff --git a/.gitignore b/.gitignore index 0b7bb2d..9fc781b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,4 @@ /node_modules /internal/server/assets/dist/* dist/ -/CHANGELOG.md /tools diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..3711f77 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,47 @@ + + +## [0.0.5](https://github.com/Bornholm/formidable/compare/0.0.4...0.0.5) (2022-08-01) + +### Features + +* ansible-vault values auto retagging in yaml format + + + +## [0.0.4](https://github.com/Bornholm/formidable/compare/0.0.3...0.0.4) (2022-06-15) + +### Features + +* add browserless mode +* **install:** fix script execution on alpine + + + +## [0.0.3](https://github.com/Bornholm/formidable/compare/0.0.2-1...0.0.3) (2022-06-15) + + + +## [0.0.2-1](https://github.com/Bornholm/formidable/compare/0.0.2...0.0.2-1) (2022-05-12) + + + +## [0.0.2](https://github.com/Bornholm/formidable/compare/install-script...0.0.2) (2022-05-12) + + + +## [install-script](https://github.com/Bornholm/formidable/compare/0.0.1...install-script) (2022-05-11) + + + +## [0.0.1](https://github.com/Bornholm/formidable/compare/0.0.0...0.0.1) (2022-05-10) + +### Features + +* values updaters +* url based multi-format loaders/decoders +* url based data loading system + + + +## 0.0.0 (2022-05-04) + diff --git a/Makefile b/Makefile index e366eda..b6c10b8 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,9 @@ GORELEASER_VERSION ?= v1.8.3 GORELEASER_ARGS ?= --auto-snapshot --rm-dist GITCHLOG_ARGS ?= SHELL := /bin/bash +RUN_INSTALL_TESTS ?= yes + +FORMIDABLE_VERSION := 0.0.5 .PHONY: help help: ## Display this help @@ -15,8 +18,12 @@ help: ## Display this help watch: deps ## Watching updated files - live reload ( set -o allexport && source .env && set +o allexport && go run -mod=readonly github.com/cortesi/modd/cmd/modd@latest ) -.PHONY: help -test: test-go test-install-script ## Executing tests +.PHONY: test +test: test-go ## Executing tests + +ifeq ($(RUN_INSTALL_TESTS), yes) +test: test-install-script +endif test-go: deps ( set -o allexport && source .env && set +o allexport && go test -v -race -count=1 $(GOTEST_ARGS) ./... ) @@ -55,9 +62,31 @@ node_modules: release: deps ( set -o allexport && source .env && set +o allexport && VERSION=$(GORELEASER_VERSION) curl -sfL https://goreleaser.com/static/run | bash /dev/stdin $(GORELEASER_ARGS) ) +.PHONY: start-release +start-release: + #git flow release start $(FORMIDABLE_VERSION) + + # Update package.json version + jq '.version = "$(FORMIDABLE_VERSION)"' package.json | sponge package.json + git add package.json + git commit -m "chore: bump to version $(FORMIDABLE_VERSION)" + + # Generate updated changelog + $(MAKE) GITCHLOG_ARGS='--next-tag $(FORMIDABLE_VERSION)' changelog + git add CHANGELOG.md + git commit -m "chore: update changelog for version $(FORMIDABLE_VERSION)" + + echo "Commit you additional modifications then execute 'make finish-release'" + +.PHONY: finish-release +finish-release: + git flow release finish -m "v$(FORMIDABLE_VERSION)" + git push --all + git push --tags + .PHONY: changelog changelog: - go run -mod=readonly github.com/git-chglog/git-chglog/cmd/git-chglog@v0.15.1 $(GITCHLOG_ARGS) + go run -mod=readonly github.com/git-chglog/git-chglog/cmd/git-chglog@v0.15.1 $(GITCHLOG_ARGS) > CHANGELOG.md install-git-hooks: git config core.hooksPath .githooks \ No newline at end of file diff --git a/README.md b/README.md index ce80b06..e0a6cdf 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ Web-based - but terminal compatible ! - little form editor using [JSONSchema](ht The generated web UI does not use Javascript and can be used with terminal browsers like [w3m](https://en.wikipedia.org/wiki/W3m) or [lynx](https://en.wikipedia.org/wiki/Lynx_(web_browser)). +> ⚠ Formidable is currently in a very alpha stage ! Expect breaking changes... + ## Install ### Manually @@ -93,6 +95,10 @@ echo '{}' | FORMIDABLE_BROWSER="firefox" frmd \ > TODO: Write doc + example +## Changelog + +[See `CHANGELOG.md`](./CHANGELOG.md) + ## Licence AGPL-3.0 diff --git a/internal/data/format/yaml/encoder_handler.go b/internal/data/format/yaml/encoder_handler.go index 809b11e..e68bbce 100644 --- a/internal/data/format/yaml/encoder_handler.go +++ b/internal/data/format/yaml/encoder_handler.go @@ -6,12 +6,15 @@ import ( "net/url" "path" "path/filepath" + "strings" "forge.cadoles.com/wpetit/formidable/internal/data/format" "github.com/pkg/errors" "gopkg.in/yaml.v3" ) +const YAMLTagAnsibleVaultValuesQueryParam = "ansible_vault" + type EncoderHandler struct{} func (d *EncoderHandler) Match(url *url.URL) bool { @@ -22,17 +25,69 @@ func (d *EncoderHandler) Match(url *url.URL) bool { } func (d *EncoderHandler) Encode(url *url.URL, data interface{}) (io.Reader, error) { - var buf bytes.Buffer + var output bytes.Buffer - encoder := yaml.NewEncoder(&buf) + encoder := yaml.NewEncoder(&output) if err := encoder.Encode(data); err != nil { return nil, errors.WithStack(err) } - return &buf, nil + if shouldTransformAnsibleVault(url) { + if err := tagAnsibleVaultValues(&output); err != nil { + return nil, errors.WithStack(err) + } + } + + return &output, nil } func NewEncoderHandler() *EncoderHandler { return &EncoderHandler{} } + +func shouldTransformAnsibleVault(url *url.URL) bool { + return !url.Query().Has(YAMLTagAnsibleVaultValuesQueryParam) || url.Query().Get(YAMLTagAnsibleVaultValuesQueryParam) == "yes" +} + +func tagAnsibleVaultValues(buf *bytes.Buffer) error { + decoder := yaml.NewDecoder(buf) + + var node yaml.Node + + if err := decoder.Decode(&node); err != nil { + return errors.WithStack(err) + } + + walkNodeTree(&node, func(node *yaml.Node) { + isAnsibleVaultNode := node.Tag == "!!str" && strings.HasPrefix(strings.TrimSpace(node.Value), "$ANSIBLE_VAULT") + if !isAnsibleVaultNode { + return + } + + node.Tag = "!vault" + node.Style = yaml.LiteralStyle | yaml.TaggedStyle + }) + + buf.Reset() + + encoder := yaml.NewEncoder(buf) + + if err := encoder.Encode(node.Content[0]); err != nil { + return errors.WithStack(err) + } + + return nil +} + +func walkNodeTree(node *yaml.Node, fn func(node *yaml.Node)) { + fn(node) + + if node.Content == nil { + return + } + + for _, sub := range node.Content { + walkNodeTree(sub, fn) + } +} diff --git a/internal/data/format/yaml/encoder_test.go b/internal/data/format/yaml/encoder_test.go new file mode 100644 index 0000000..5979fdc --- /dev/null +++ b/internal/data/format/yaml/encoder_test.go @@ -0,0 +1,88 @@ +package yaml + +import ( + "fmt" + "io" + "net/url" + "os" + "os/exec" + "strings" + "testing" + + "github.com/pkg/errors" + yaml "gopkg.in/yaml.v3" +) + +// YAML string containing an ansible-vault encrypted variable +const ansibleVaultYAML = ` +unencrypted: foo +encrypted: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 63393636613562663937383964323839376239663230366130386566393131313963386265303632 + 3133356532346437653338343032303732646530303431660a383862353766326334306138613734 + 36313438626564623435373365616531353533663765663335616134656430323134323537336661 + 3437653863343331370a393136653735643333373962633631663539653664313936303964303866 + 3933 +` + +func TestEncoderAnsibleVault(t *testing.T) { + _, err := exec.LookPath("ansible") + if err != nil { + t.Skip("The 'ansible' command seems not to be available on this system. Skipping.") + + return + } + + var data interface{} + + if err := yaml.Unmarshal([]byte(ansibleVaultYAML), &data); err != nil { + t.Fatal(errors.WithStack(err)) + } + + encoder := NewEncoderHandler() + + url, err := url.Parse("stdout://local.yml?ansible_vault=yes") + if err != nil { + t.Fatal(errors.WithStack(err)) + } + + reader, err := encoder.Encode(url, data) + if err != nil { + t.Fatal(errors.WithStack(err)) + } + + temp, err := os.CreateTemp(os.TempDir(), "formidable_test_*.yml") + if err != nil { + t.Fatal(errors.WithStack(err)) + } + + defer func() { + if err := os.Remove(temp.Name()); err != nil { + panic(errors.WithStack(err)) + } + }() + + t.Logf("Writing encoded YAML content in file '%s'...", temp.Name()) + + if _, err := io.Copy(temp, reader); err != nil { + t.Fatal(errors.WithStack(err)) + } + + args := []string{ + "localhost", + "-m", "debug", + "--vault-password-file", "./testdata/vault.txt", + "-e", fmt.Sprintf("@%s", temp.Name()), + "-a", "var=encrypted", + } + + t.Logf("Running command 'ansible %s'", strings.Join(args, " ")) + + cmd := exec.Command("ansible", args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + if err := cmd.Run(); err != nil { + t.Fatal(errors.WithStack(err)) + } +} diff --git a/internal/data/format/yaml/testdata/vault.txt b/internal/data/format/yaml/testdata/vault.txt new file mode 100644 index 0000000..b7e8e2b --- /dev/null +++ b/internal/data/format/yaml/testdata/vault.txt @@ -0,0 +1 @@ +formidable \ No newline at end of file diff --git a/internal/server/template/blocks/form_input_string.html.tmpl b/internal/server/template/blocks/form_input_string.html.tmpl index f7750d9..7bd5275 100644 --- a/internal/server/template/blocks/form_input_string.html.tmpl +++ b/internal/server/template/blocks/form_input_string.html.tmpl @@ -1,9 +1,13 @@ {{define "form_input_string"}} {{ $fullProperty := getFullProperty .Parent .Property }} {{ $value := getValue .Defaults .Values $fullProperty }} - + value="{{ $value }}" /> */}} + {{end}} \ No newline at end of file diff --git a/package.json b/package.json index a05931f..f2477dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "formidable", - "version": "0.0.4", + "version": "0.0.5", "description": "", "main": "index.js", "dependencies": {},