Source file src/crypto/internal/cryptotest/wycheproof/_schema/schema_gen.go

     1  // Copyright 2026 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // A stand-alone Go module that generates ../schema.go using the
     6  // upstream Wycheproof JSON schema documents.
     7  //
     8  // We maintain this in a separate Go module and vendor the resulting
     9  // generated .go code to avoid the standard library taking a direct
    10  // dependency on the c2sp/wycheproof or atombender/go-jsonschema modules.
    11  
    12  package main
    13  
    14  import (
    15  	"bufio"
    16  	"fmt"
    17  	"io/fs"
    18  	"log"
    19  	"os"
    20  	"path/filepath"
    21  	"strings"
    22  
    23  	"github.com/atombender/go-jsonschema/pkg/generator"
    24  	"github.com/c2sp/wycheproof"
    25  )
    26  
    27  func main() {
    28  	ouputName := "schema.go"
    29  	cfg := generator.Config{
    30  		DefaultPackageName: "wycheproof",
    31  		DefaultOutputName:  ouputName,
    32  		Tags:               []string{"json"},
    33  		Warner: func(message string) {
    34  			log.Printf("go-jsonschema: %s", message)
    35  		},
    36  	}
    37  	gen, err := generator.New(cfg)
    38  	if err != nil {
    39  		log.Fatal(err)
    40  	}
    41  
    42  	// Without upstream modifications we can't use the embedded Wycheproof
    43  	// schema FS directly w/ go-jsonschema and instead make files in a tempdir
    44  	// on the native FS. See https://github.com/omissis/go-jsonschema/issues/495
    45  	schemaDir, err := os.MkdirTemp("", "*-wycheproof")
    46  	if err != nil {
    47  		log.Fatal(err)
    48  	}
    49  	defer os.RemoveAll(schemaDir)
    50  
    51  	rawSchemas, _ := fs.ReadDir(wycheproof.Schemas, ".")
    52  	for _, entry := range rawSchemas {
    53  		entryName := entry.Name()
    54  		schemaFile := filepath.Join(schemaDir, entryName)
    55  
    56  		schemaData, err := fs.ReadFile(wycheproof.Schemas, entryName)
    57  		if err != nil {
    58  			log.Fatalf("reading %s: %v", entryName, err)
    59  		}
    60  		err = os.WriteFile(schemaFile, schemaData, 0644)
    61  		if err != nil {
    62  			log.Fatalf("writing %s: %v", schemaFile, err)
    63  		}
    64  	}
    65  
    66  	// Note: it's important we process schemas in a second pass after writing
    67  	// **all** of the schema file content to disk so that go-jsonschema can
    68  	// resolve cross-file references.
    69  	for _, entry := range rawSchemas {
    70  		entryName := entry.Name()
    71  		schemaFile := filepath.Join(schemaDir, entryName)
    72  
    73  		err = gen.DoFile(schemaFile)
    74  		if err != nil {
    75  			log.Fatalf("processing %s: %v", schemaFile, err)
    76  		}
    77  	}
    78  
    79  	sources, err := gen.Sources()
    80  	if err != nil {
    81  		log.Fatalf("error generating sources: %v\n", err)
    82  	}
    83  	if sourceCount := len(sources); sourceCount != 1 {
    84  		log.Fatalf("expected to generate 1 source file, got %d\n", sourceCount)
    85  	}
    86  	content, ok := sources[ouputName]
    87  	if !ok {
    88  		log.Fatalf("missing generated %q output file source", ouputName)
    89  	}
    90  	outFile := filepath.Join("../", ouputName)
    91  	if err := os.WriteFile(outFile, content, 0644); err != nil {
    92  		log.Fatalf("error writing file %s: %v\n", outFile, err)
    93  	}
    94  
    95  	// Write a sibling file recording the Wycheproof module version that the
    96  	// generated schema.go was produced against. The wycheproof package uses
    97  	// this constant to fetch matching test vectors at runtime. We avoid reading
    98  	// go.sum at test time because it might not be available (e.g. if the test
    99  	// binary was copied to a remote machine).
   100  	version, err := wycheproofVersionFromSum("go.sum")
   101  	if err != nil {
   102  		log.Fatalf("extracting wycheproof version: %v", err)
   103  	}
   104  	const versionFile = "../schemaversion.go"
   105  	versionSrc := fmt.Sprintf(`// Copyright 2026 The Go Authors. All rights reserved.
   106  // Use of this source code is governed by a BSD-style
   107  // license that can be found in the LICENSE file.
   108  
   109  // Code generated by _schema/schema_gen.go, DO NOT EDIT.
   110  
   111  package wycheproof
   112  
   113  // wycheproofVersion is the github.com/c2sp/wycheproof module version that
   114  // schema.go was generated against.
   115  const wycheproofVersion = %q
   116  `, version)
   117  	if err := os.WriteFile(versionFile, []byte(versionSrc), 0644); err != nil {
   118  		log.Fatalf("writing %s: %v", versionFile, err)
   119  	}
   120  }
   121  
   122  // wycheproofVersionFromSum returns the github.com/c2sp/wycheproof module
   123  // version recorded in the given go.sum file.
   124  func wycheproofVersionFromSum(path string) (string, error) {
   125  	f, err := os.Open(path)
   126  	if err != nil {
   127  		return "", err
   128  	}
   129  	defer f.Close()
   130  
   131  	var version string
   132  	found := 0
   133  	scanner := bufio.NewScanner(f)
   134  	for scanner.Scan() {
   135  		fields := strings.Fields(scanner.Text())
   136  		if len(fields) == 3 && fields[0] == "github.com/c2sp/wycheproof" {
   137  			version = strings.TrimSuffix(fields[1], "/go.mod")
   138  			found++
   139  		}
   140  	}
   141  	if err := scanner.Err(); err != nil {
   142  		return "", err
   143  	}
   144  	switch {
   145  	case found == 0:
   146  		return "", fmt.Errorf("%s: missing github.com/c2sp/wycheproof entry", path)
   147  	case found > 2:
   148  		return "", fmt.Errorf("%s: %d github.com/c2sp/wycheproof entries (run 'go mod tidy')", path, found)
   149  	}
   150  	return version, nil
   151  }
   152  

View as plain text