CodeSampleX

샘플

github.com/tailscale/tscert v0.0.0-20240608151842-d3f834017e53: fetch TLS certificate using tailscale tscert GetCertificate with mocked daemon transport

검증된 샘플 — golang github.com/tailscale/tscert v0.0.0-20240608151842-d3f834017e53: fetch TLS certificate using tailscale tscert GetCertificate with mocked…

sha256:fa827b92eaa8464bf3278089b147f12ba05fcd79912fd7bcff96b5d5d7c842b2

이 네트워크가 제공하는 것은 하나입니다. 빌드되는 샘플. 샌드박스에서 돌리고 서명된 영수증을 보관합니다. 등급을 매기지 않고 무엇도 보증하지 않습니다 — 같은 코드가 당신 환경에서 빌드되는지는 측정한 적이 없습니다. 통과한 계약 영수증을 낸 서로 다른 서명 키의 수입니다. 하나면 작성자 혼자이고, 둘 이상이면 다른 사람도 빌드했다는 뜻입니다. 키는 스스로 만드는 것이고 뒤에 등록된 신원이 없으므로, 세는 것은 사람이 아니라 키입니다. MIT-0

실행 증거

선언된 환경과 서명된 실행을 분리해 두었습니다. 이 샘플이 무엇을 어디서 실행했는지 그대로 볼 수 있습니다.

증거 기준
서명된 컨트랙트 통과
검증 영수증
1
빌드한 서명 키
1
선언된 환경 linux 24 · ubuntu · glibc 2.39 x64 go

검증 실행 환경

환경 컨트랙트 단계 실행일
go 1.26 · linux alpine/x64 · docker ed25519:c1973797be207ac4 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · golang@1golang:1.26-alpine@sha256:28d89ee9cc0f…
2026-08-23

케이스

HOW
목표
fetch TLS certificate using tailscale tscert GetCertificate with mocked daemon transport
패키지
심벌
  • tscert.GetCertificate
생성일
2026-08-23T16:47:42Z

컨트랙트

  1. tscert.GetCertificate returns an error matching 'no SNI ServerName' when passed nil ClientHelloInfo or an empty ServerName
  2. tscert.GetCertificate fetches and returns a tls.Certificate from LocalAPI cert endpoint (/localapi/v0/cert/<domain>?type=pair) for a full domain name
  3. tscert.GetCertificate expands a bare hostname to FQDN using the LocalAPI status endpoint (/localapi/v0/status) CertDomains when ServerName contains no period
  4. tscert.TailscaledTransport allows mock HTTP transport override for daemon LocalAPI interactions

파일

  • PROMPT.md
  • contract_test.go
  • csx.json
  • go.mod
  • go.sum
  • spec.json

소스 아티팩트 내려받기 (tar.gz)

소스

PROMPT.md
Clean-room public code sample — generation instructions

Write a brand-new, minimal, self-contained code sample in this clean-room directory.
Do not copy, paraphrase, or reference any existing project source. Work only from this spec.

A csx.json manifest scaffold already exists. Do not recreate it from memory. Preserve its case.goal, packages and symbols; fill its empty case.contract with exact assertions and correct its environment, commands and verifierAdapter for the files you generate.

Goal: fetch TLS certificate using tailscale tscert GetCertificate with mocked daemon transport
Kind: HOW

Use EXACTLY these public packages and versions:
  - pkg:golang/github.com/tailscale/tscert@v0.0.0-20240608151842-d3f834017e53
Demonstrate these symbols/APIs:
  - tscert.GetCertificate

Rules:
  - One focused purpose; the smallest project that proves the goal.
  - Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
  - Pin every dependency with a lockfile so resolution is reproducible.
  - No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
  - No personal names, emails, company names, or project identifiers of any kind.
  - No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
  - Keep it under 200 files and 256KB packed.
contract_test.go
package sample

import (
	"bytes"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/json"
	"encoding/pem"
	"io"
	"math/big"
	"net/http"
	"strings"
	"testing"
	"time"

	"github.com/tailscale/tscert"
)

type mockTransport func(*http.Request) (*http.Response, error)

func (f mockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	return f(req)
}

func generateCertPairPEM(domain string) ([]byte, []byte, error) {
	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		return nil, nil, err
	}

	template := x509.Certificate{
		SerialNumber: big.NewInt(1),
		Subject:      pkix.Name{CommonName: domain},
		DNSNames:     []string{domain},
		NotBefore:    time.Now().Add(-time.Hour),
		NotAfter:     time.Now().Add(24 * time.Hour),
		KeyUsage:     x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
		ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
	}

	certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
	if err != nil {
		return nil, nil, err
	}

	keyDER, err := x509.MarshalECPrivateKey(key)
	if err != nil {
		return nil, nil, err
	}

	keyPEM := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: keyDER})
	certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})

	return keyPEM, certPEM, nil
}

func TestGetCertificateContract(t *testing.T) {
	// Assert 1: nil ClientHelloInfo returns "no SNI ServerName" error
	if _, err := tscert.GetCertificate(nil); err == nil || !strings.Contains(err.Error(), "no SNI ServerName") {
		t.Fatalf("expected 'no SNI ServerName' error for nil info, got %v", err)
	}

	// Assert 2: empty ServerName returns "no SNI ServerName" error
	if _, err := tscert.GetCertificate(&tls.ClientHelloInfo{ServerName: ""}); err == nil || !strings.Contains(err.Error(), "no SNI ServerName") {
		t.Fatalf("expected 'no SNI ServerName' error for empty ServerName, got %v", err)
	}

	domain := "myserver.example.com"
	keyPEM, certPEM, err := generateCertPairPEM(domain)
	if err != nil {
		t.Fatalf("failed to generate cert pair: %v", err)
	}

	pairPayload := append(keyPEM, certPEM...)

	// Configure mock transport for daemon LocalAPI
	tscert.TailscaledTransport = mockTransport(func(req *http.Request) (*http.Response, error) {
		switch req.URL.Path {
		case "/localapi/v0/status":
			body, _ := json.Marshal(map[string]interface{}{
				"Version":      "1.0.0",
				"BackendState": "Running",
				"CertDomains":  []string{domain},
			})
			return &http.Response{
				StatusCode: http.StatusOK,
				Body:       io.NopCloser(bytes.NewReader(body)),
				Header:     make(http.Header),
			}, nil

		case "/localapi/v0/cert/" + domain:
			if req.URL.Query().Get("type") != "pair" {
				return &http.Response{
					StatusCode: http.StatusBadRequest,
					Body:       io.NopCloser(bytes.NewReader([]byte("bad query"))),
					Header:     make(http.Header),
				}, nil
			}
			return &http.Response{
				StatusCode: http.StatusOK,
				Body:       io.NopCloser(bytes.NewReader(pairPayload)),
				Header:     make(http.Header),
			}, nil

		default:
			return &http.Response{
				StatusCode: http.StatusNotFound,
				Body:       io.NopCloser(bytes.NewReader([]byte("not found"))),
				Header:     make(http.Header),
			}, nil
		}
	})

	// Assert 3: GetCertificate with FQDN fetches cert pair from LocalAPI and returns tls.Certificate
	cert, err := tscert.GetCertificate(&tls.ClientHelloInfo{ServerName: domain})
	if err != nil {
		t.Fatalf("GetCertificate failed for FQDN: %v", err)
	}
	if cert == nil || len(cert.Certificate) == 0 {
		t.Fatalf("expected non-empty certificate for FQDN")
	}

	// Assert 4: GetCertificate with bare label expands domain using daemon status and returns tls.Certificate
	certBare, err := tscert.GetCertificate(&tls.ClientHelloInfo{ServerName: "myserver"})
	if err != nil {
		t.Fatalf("GetCertificate failed for bare label: %v", err)
	}
	if certBare == nil || len(certBare.Certificate) == 0 {
		t.Fatalf("expected non-empty certificate for bare label")
	}
}
csx.json
{"case":{"caseId":"case:sha256:bd538166c6f57e8215aedefdbc3482a67e328f38adf3c371cfe04d3f2e9069fb","contract":["tscert.GetCertificate returns an error matching 'no SNI ServerName' when passed nil ClientHelloInfo or an empty ServerName","tscert.GetCertificate fetches and returns a tls.Certificate from LocalAPI cert endpoint (/localapi/v0/cert/\u003cdomain\u003e?type=pair) for a full domain name","tscert.GetCertificate expands a bare hostname to FQDN using the LocalAPI status endpoint (/localapi/v0/status) CertDomains when ServerName contains no period","tscert.TailscaledTransport allows mock HTTP transport override for daemon LocalAPI interactions"],"goal":"fetch TLS certificate using tailscale tscert GetCertificate with mocked daemon transport","kind":"HOW","packages":["pkg:golang/github.com/tailscale/tscert@v0.0.0-20240608151842-d3f834017e53"],"schemaVersion":1,"symbols":["tscert.GetCertificate"]},"contractCommand":["go","test","./..."],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"golang","libc":"glibc","libcVersion":"2.39","os":"linux","osVersionBucket":"24","packageManager":"go","schemaVersion":1},"license":"MIT-0","packages":["pkg:golang/github.com/tailscale/tscert@v0.0.0-20240608151842-d3f834017e53"],"schemaVersion":1,"subject":"pkg:golang/github.com/tailscale/tscert@v0.0.0-20240608151842-d3f834017e53","symbols":["tscert.GetCertificate"],"verifierAdapter":"golang@1"}
go.mod
module sample

go 1.22

require github.com/tailscale/tscert v0.0.0-20240608151842-d3f834017e53

require (
	github.com/Microsoft/go-winio v0.6.0 // indirect
	github.com/mitchellh/go-ps v1.0.0 // indirect
	golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
	golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
	golang.org/x/tools v0.1.12 // indirect
)
go.sum
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/tailscale/tscert v0.0.0-20240608151842-d3f834017e53 h1:uxMgm0C+EjytfAqyfBG55ZONKQ7mvd7x4YYCWsf8QHQ=
github.com/tailscale/tscert v0.0.0-20240608151842-d3f834017e53/go.mod h1:kNGUQ3VESx3VZwRwA9MSCUegIl6+saPL8Noq82ozCaU=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
spec.json
{
  "schemaVersion": 1,
  "goal": "fetch TLS certificate using tailscale tscert GetCertificate with mocked daemon transport",
  "kind": "HOW",
  "packages": [
    "pkg:golang/github.com/tailscale/tscert@v0.0.0-20240608151842-d3f834017e53"
  ],
  "symbols": [
    "tscert.GetCertificate"
  ]
}

오리진 시더

익명