Fix HTML character escaping in maintained-apps JSON output (#35819)

- Replace json.MarshalIndent with json.Encoder using
SetEscapeHTML(false)
- Fixes both processOutput() and updateAppsListFile() functions
- Add test to verify HTML characters are preserved
- Regenerate yubico-yubikey-manager manifest to demonstrate fix

Previously, HTML tags and special characters (<, >, &) were being
escaped as Unicode sequences (\u003c, \u003e, \u0026) in JSON output.
This affected both app descriptions with HTML links and shell scripts
with redirect operators.
This commit is contained in:
Mitch Francese
2025-11-18 09:49:39 -05:00
committed by GitHub
parent 6e635e7888
commit 7a46fa2f22
3 changed files with 62 additions and 6 deletions
+13 -4
View File
@@ -1,6 +1,7 @@
package main
import (
"bytes"
"context"
"encoding/json"
"flag"
@@ -70,10 +71,14 @@ func processOutput(ctx context.Context, app *maintained_apps.FMAManifestApp) err
Refs: map[string]string{app.UninstallScriptRef: app.UninstallScript, app.InstallScriptRef: app.InstallScript},
}
outBytes, err := json.MarshalIndent(outFile, "", " ")
if err != nil {
var buf bytes.Buffer
encoder := json.NewEncoder(&buf)
encoder.SetEscapeHTML(false)
encoder.SetIndent("", " ")
if err := encoder.Encode(outFile); err != nil {
return ctxerr.Wrap(ctx, err, "marshaling output app manifest")
}
outBytes := buf.Bytes()
outDir := path.Join(maintained_apps.OutputPath, app.SlugAppName())
@@ -133,10 +138,14 @@ func updateAppsListFile(ctx context.Context, outApp *maintained_apps.FMAManifest
// Keep existing order
slices.SortFunc(outputAppsFile.Apps, func(a, b maintained_apps.FMAListFileApp) int { return strings.Compare(a.Slug, b.Slug) })
updatedFile, err := json.MarshalIndent(outputAppsFile, "", " ")
if err != nil {
var buf bytes.Buffer
encoder := json.NewEncoder(&buf)
encoder.SetEscapeHTML(false)
encoder.SetIndent("", " ")
if err := encoder.Encode(outputAppsFile); err != nil {
return ctxerr.Wrap(ctx, err, "marshaling updated output apps file")
}
updatedFile := buf.Bytes()
if err := os.WriteFile(appListFilePath, updatedFile, 0o644); err != nil {
return ctxerr.Wrap(ctx, err, "writing updated output apps file")
+47
View File
@@ -0,0 +1,47 @@
package main
import (
"bytes"
"encoding/json"
"strings"
"testing"
)
func TestJSONEncoderPreservesHTML(t *testing.T) {
testData := struct {
Description string `json:"description"`
}{
Description: `Test with HTML: <a href="https://example.com">link</a> & special chars < >`,
}
// Test with SetEscapeHTML(false)
var buf bytes.Buffer
encoder := json.NewEncoder(&buf)
encoder.SetEscapeHTML(false)
if err := encoder.Encode(testData); err != nil {
t.Fatalf("Failed to encode: %v", err)
}
result := buf.String()
// Verify HTML characters are preserved, not escaped
if strings.Contains(result, `\u003c`) {
t.Error("Found escaped '<' character (\\u003c) - HTML escaping is still enabled")
}
if strings.Contains(result, `\u003e`) {
t.Error("Found escaped '>' character (\\u003e) - HTML escaping is still enabled")
}
if strings.Contains(result, `\u0026`) {
t.Error("Found escaped '&' character (\\u0026) - HTML escaping is still enabled")
}
// Verify HTML characters are present (note: quotes inside JSON are still escaped)
if !strings.Contains(result, `<a href=\"https://example.com\">`) {
t.Error("HTML anchor tag was not preserved correctly")
}
if !strings.Contains(result, ` & `) {
t.Error("Ampersand character was not preserved correctly")
}
t.Logf("Successfully preserved HTML in JSON output: %s", result)
}