refactor(workflows): remove license root certificate injection from build process

- Eliminated the steps for injecting commercial license root certificates from GitHub Secrets in both Linux and macOS workflows, streamlining the build process.
- Updated the `inspect` command to load commercial license information directly, enhancing the application's licensing capabilities without relying on external secrets during the build.
This commit is contained in:
Max 2026-03-27 15:46:01 +08:00
parent aa5a16c4a7
commit ac8cdaeda9
8 changed files with 133 additions and 43 deletions

View file

@ -35,9 +35,6 @@ jobs:
aws configure set default.s3.endpoint_url https://$R2_ACCOUNT_ID.r2.cloudflarestorage.com
- name: Build
env:
ROOT_CA_1: ${{ secrets.YAO_ROOT_CA_1_PEM }}
ROOT_CA_2: ${{ secrets.YAO_ROOT_CA_2_PEM }}
run: |
export PATH=$PATH:/github/home/go/bin
@ -51,16 +48,6 @@ jobs:
git clone https://github.com/yaoapp/yao-init.git /app/yao-init
git clone https://github.com/yaoapp/yao.git /app/yao
# Inject commercial license root certificates from GitHub Secrets
if [ -n "$ROOT_CA_1" ]; then
echo "$ROOT_CA_1" | base64 -d > /app/yao/commercial/roots/root-ca-1.pem
echo "Injected root-ca-1.pem"
fi
if [ -n "$ROOT_CA_2" ]; then
echo "$ROOT_CA_2" | base64 -d > /app/yao/commercial/roots/root-ca-2.pem
echo "Injected root-ca-2.pem"
fi
# Extract libv8
files=$(find /app/v8go -name "libv8*.zip")
for file in $files; do

View file

@ -105,20 +105,6 @@ jobs:
rm -f share/const.go.bak
grep 'const VERSION' share/const.go
- name: Inject License Root Certificates
env:
ROOT_CA_1: ${{ secrets.YAO_ROOT_CA_1_PEM }}
ROOT_CA_2: ${{ secrets.YAO_ROOT_CA_2_PEM }}
run: |
if [ -n "$ROOT_CA_1" ]; then
echo "$ROOT_CA_1" | base64 -d > commercial/roots/root-ca-1.pem
echo "Injected root-ca-1.pem"
fi
if [ -n "$ROOT_CA_2" ]; then
echo "$ROOT_CA_2" | base64 -d > commercial/roots/root-ca-2.pem
echo "Injected root-ca-2.pem"
fi
- name: Setup Go
uses: actions/setup-go@v5
with:

View file

@ -16,6 +16,7 @@ var inspectCmd = &cobra.Command{
Long: L("Show app configure"),
Run: func(cmd *cobra.Command, args []string) {
Boot()
commercial.Load(config.Conf.Root, "yao")
engine.InspectExtTools()
res := maps.Map{
"version": share.VERSION,

View file

@ -2,6 +2,7 @@ package commercial
import (
"crypto/x509"
_ "embed"
"math/big"
"os"
"path/filepath"
@ -10,6 +11,12 @@ import (
"time"
)
//go:embed testdata/test-intermediate-ca.pem
var testIntermediateCAPEM []byte
//go:embed testdata/test-license.pem
var testLicensePEM []byte
// withTestRootPool temporarily replaces the root pool and revocation list
// for testing, restoring originals on cleanup.
func withTestRootPool(t *testing.T, ca *testCA, revoked []*big.Int) {
@ -419,6 +426,59 @@ func TestDefaultLicenseAndHelpers(t *testing.T) {
}
}
// TestRealChainIntermediate verifies a certificate signed by a real test intermediate CA,
// which in turn is signed by the real Root CA 1 embedded in the binary.
// Uses testdata/test-intermediate-ca.pem and testdata/test-license.pem generated by
// /Volumes/DATA/Work/Yaobots/keys/gen-test-certs.go.
func TestRealChainIntermediate(t *testing.T) {
// Use the real embedded root pool (not overridden)
dir := t.TempDir()
if err := os.WriteFile(filepath.Join(dir, "license.pem"), testLicensePEM, 0644); err != nil {
t.Fatal(err)
}
License = DefaultLicense()
Load(dir, "yao")
if !License.Valid {
t.Fatalf("expected Valid=true with real chain, got error: %s", License.Error)
}
if License.Edition != "enterprise" {
t.Fatalf("expected Edition=enterprise, got %s", License.Edition)
}
if !License.HasProduct("yao") {
t.Fatalf("expected HasProduct(yao)=true, got products: %v", License.Product)
}
if !License.Permissions.AllowBrandingRemoval {
t.Fatal("expected AllowBrandingRemoval=true")
}
if !License.Permissions.AllowWhiteLabel {
t.Fatal("expected AllowWhiteLabel=true")
}
if !License.IsLevel("enterprise") {
t.Fatalf("expected IsLevel(enterprise)=true, edition=%s", License.Edition)
}
}
// TestRealIntermediateCACert parses the embedded test intermediate CA cert
// and verifies it is signed by the real Root CA 1.
func TestRealIntermediateCACert(t *testing.T) {
intCert, err := ParsePEMChain(testIntermediateCAPEM)
if err != nil || len(intCert) == 0 {
t.Fatalf("failed to parse test intermediate CA: %v", err)
}
opts := x509.VerifyOptions{
Roots: RootPool(),
CurrentTime: time.Now(),
}
// Intermediate CA certs are not end-entity; relax KeyUsages check
opts.KeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageAny}
if _, err := intCert[0].Verify(opts); err != nil {
t.Fatalf("test intermediate CA not verified by real root pool: %v", err)
}
}
func TestCertsSubdirectoryFallback(t *testing.T) {
root, err := generateRootCA("Test Root CA", 10*365*24*time.Hour)
if err != nil {

View file

@ -1,14 +1,13 @@
-----BEGIN CERTIFICATE-----
MIICFzCCAZygAwIBAgIQYJYI6zEyHfyDlfFW2p4NHDAKBggqhkjOPQQDAzBLMQsw
CQYDVQQGEwJDTjEhMB8GA1UEChMYSW5maW5pdGUgV2lzZG9tIFNvZnR3YXJlMRkw
FwYDVQQDExBZYW8gVGVzdCBSb290IENBMB4XDTI2MDMyNzAzMzYxMVoXDTM2MDMy
NDA0MzYxMVowSzELMAkGA1UEBhMCQ04xITAfBgNVBAoTGEluZmluaXRlIFdpc2Rv
bSBTb2Z0d2FyZTEZMBcGA1UEAxMQWWFvIFRlc3QgUm9vdCBDQTB2MBAGByqGSM49
AgEGBSuBBAAiA2IABNe4Y3nl17lCgK3dZaGFYPdeutdm/hdprjwynJPfGBnw84oE
UBIgm7Nd5hpM57xZak9oH4ol58sOTxjWL492JWX+jU9pRUYn042HA4imSmmrxzP3
83m8Kn9VcYSEKPJzmKNFMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB
Af8CAQEwHQYDVR0OBBYEFGh4E/o55y4xR3qa7ZUSIVoxpHdlMAoGCCqGSM49BAMD
A2kAMGYCMQDLhwvg8SDmMiwHCejwtLBozFLcdkys/MoFVnueUE1RAQo1G0CitB/y
UJaYwCnV3j0CMQDe09TLfSA/69XDsv4ueNq9UtY9+ysEzkD2zxupOL1MYSPGNN0a
/ct7CLnLDOnRsN8=
MIICATCCAYegAwIBAgIBATAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJDTjEhMB8G
A1UEChMYSW5maW5pdGUgV2lzZG9tIFNvZnR3YXJlMRYwFAYDVQQDEw1ZYW8gUm9v
dCBDQSAxMB4XDTI2MDMyNzA2MzYxMloXDTM2MDMyNDA3MzYxMlowSDELMAkGA1UE
BhMCQ04xITAfBgNVBAoTGEluZmluaXRlIFdpc2RvbSBTb2Z0d2FyZTEWMBQGA1UE
AxMNWWFvIFJvb3QgQ0EgMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDg0J9BxEjOn
Os5D7i3fzFxFOlLR13nanGIjde3bqaohZoD7fCGtfVd5+2vq7y/UOQRAvbu5/RzK
e1S9LFlWjFppdpgbeegd0dMCDEe/9tJknAO35MpWCJxmU7f3Jo4QE6NFMEMwDgYD
VR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQIwHQYDVR0OBBYEFB6XvPEQ
D+g1yTpwyPj3Quwu9wuXMAoGCCqGSM49BAMDA2gAMGUCMFc2K+Xggn5GRo181pAU
aU43Sud8kyXlOuMMpQ/+mfqVNKJhPN75VditQoGiau8VjQIxAO4lJGpuG8f/j4mE
6WaF1x4x45GKc6zaHtgpVUTaX2FazAqkZgSYy57Ipnx0UWrD+A==
-----END CERTIFICATE-----

View file

@ -1,4 +1,13 @@
-----BEGIN PLACEHOLDER-----
This is a development placeholder. The real backup root certificate will be
injected by the release workflow via GitHub Secrets before compilation.
-----END PLACEHOLDER-----
-----BEGIN CERTIFICATE-----
MIICATCCAYegAwIBAgIBAjAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJDTjEhMB8G
A1UEChMYSW5maW5pdGUgV2lzZG9tIFNvZnR3YXJlMRYwFAYDVQQDEw1ZYW8gUm9v
dCBDQSAyMB4XDTI2MDMyNzA2MzYxMloXDTM2MDMyNDA3MzYxMlowSDELMAkGA1UE
BhMCQ04xITAfBgNVBAoTGEluZmluaXRlIFdpc2RvbSBTb2Z0d2FyZTEWMBQGA1UE
AxMNWWFvIFJvb3QgQ0EgMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABB01XlJON6el
vpif5oCD4Mmdvj5muXeq02ZGHSWSrqrxkzUbCbI5LpwURiGObOVnGMw2MT76hW0P
Eq28XDTiXxnVqrjkE95ppl5npgnqMv3PTODizkak2HSXqwuIESLip6NFMEMwDgYD
VR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQIwHQYDVR0OBBYEFNHmPR9D
aXyJZQng5BcwhaB9H9CsMAoGCCqGSM49BAMDA2gAMGUCMQDkQlbGE1yZq7cLele8
4S+RiYhj3sTsZejU5215f0doOfDka18iv5BeclELP2aQOeQCMFqfeeSKS9SFrHly
SRfZV9o/qxQM3i9EgV1l/D7T9qzPZWR2YcTUSS8TTcwxyIiLAA==
-----END CERTIFICATE-----

View file

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICLzCCAbSgAwIBAgICIykwCgYIKoZIzj0EAwMwSDELMAkGA1UEBhMCQ04xITAf
BgNVBAoTGEluZmluaXRlIFdpc2RvbSBTb2Z0d2FyZTEWMBQGA1UEAxMNWWFvIFJv
b3QgQ0EgMTAeFw0yNjAzMjcwNjQyNTlaFw0yODAzMjYwNzQyNTlaMFMxCzAJBgNV
BAYTAkNOMSEwHwYDVQQKExhJbmZpbml0ZSBXaXNkb20gU29mdHdhcmUxITAfBgNV
BAMTGFlhbyBUZXN0IEludGVybWVkaWF0ZSBDQTB2MBAGByqGSM49AgEGBSuBBAAi
A2IABHG2U+9ScPK/NBfGW3jgg8fNVH/NfGcPOkypKHonsIad1fG4H+kUtEyyQTvP
4of6FO8FmnvyezMdtaEPlUxRLmYPW9dqsnCZswZasgQLOd5b+qxe4bFY86yla2Iq
HxWIyKNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD
VR0OBBYEFHoGH8BliDziOpSBraPs5+ehyWBMMB8GA1UdIwQYMBaAFB6XvPEQD+g1
yTpwyPj3Quwu9wuXMAoGCCqGSM49BAMDA2kAMGYCMQCkN/W+unUuHyP/2phruVv4
itASDUZfm3ZDGS450ixZO9OMQZ9t/dNv1HyfN0M9wCMCMQDoYKwveqllF7XvSPQp
fBfRbxsR+t8LpJqzNXMGgzUpKuZ/KLBAjnbZgwCCGCR1zN0=
-----END CERTIFICATE-----

34
commercial/testdata/test-license.pem vendored Normal file
View file

@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIDSzCCAtGgAwIBAgIDAV+RMAoGCCqGSM49BAMDMFMxCzAJBgNVBAYTAkNOMSEw
HwYDVQQKExhJbmZpbml0ZSBXaXNkb20gU29mdHdhcmUxITAfBgNVBAMTGFlhbyBU
ZXN0IEludGVybWVkaWF0ZSBDQTAeFw0yNjAzMjcwNjQyNTlaFw0yNzAzMjcwNzQy
NTlaMD4xCzAJBgNVBAYTAkNOMRkwFwYDVQQKExBZYW8gQXBwIFRlc3QgT3JnMRQw
EgYDVQQDEwtZYW8gRGV2IEFwcDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLBN
Ikb7MXULLpHymC2qV2YjB2pbUjuB7hP6tQa/5aN82o5W7lxMUF2jP4kuptMeaiXj
QyKrtlhDWZzAJ/HshhmjggGnMIIBozAOBgNVHQ8BAf8EBAMCB4AwDwYDVR0lBAgw
BgYEVR0lADAfBgNVHSMEGDAWgBR6Bh/AZYg84jqUga2j7OfnoclgTDAaBgNVHREE
EzARgQ9kZXZAeWFvYXBwcy5jb20wFQYKKwYBBAH1ewEBAQQHeWFvLHRhaTAYBgor
BgEEAfV7AQECBAplbnRlcnByaXNlMA8GCisGAQQB9XsBAgEEATAwDwYKKwYBBAH1
ewECAgQBMDAPBgorBgEEAfV7AQIDBAEwMA8GCisGAQQB9XsBAgQEATAwDwYKKwYB
BAH1ewECBQQBMDAPBgorBgEEAfV7AQIGBAEwMBIGCisGAQQB9XsBAwEEBHRydWUw
EgYKKwYBBAH1ewEDAgQEdHJ1ZTASBgorBgEEAfV7AQMDBAR0cnVlMBIGCisGAQQB
9XsBAwQEBHRydWUwEgYKKwYBBAH1ewEDBQQEdHJ1ZTASBgorBgEEAfV7AQMGBAR0
cnVlMBcGCisGAQQB9XsBAwcECWRlZGljYXRlZDAbBgorBgEEAfV7AQQCBA1URVNU
LTIwMjYtMDAxMAoGCCqGSM49BAMDA2gAMGUCMDKJ9oL04HJa0Djh5PbB/bEDEpZA
nS/UWyfaXCbgqQeI+rIhjIXFsEC9CXeFXfa5iwIxAKmTybVyE0QkIQqEifB50LLy
8FXcL1owzKWB5JHn2rTVGr2cSf2SrBQJMefFWiLEUQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICLzCCAbSgAwIBAgICIykwCgYIKoZIzj0EAwMwSDELMAkGA1UEBhMCQ04xITAf
BgNVBAoTGEluZmluaXRlIFdpc2RvbSBTb2Z0d2FyZTEWMBQGA1UEAxMNWWFvIFJv
b3QgQ0EgMTAeFw0yNjAzMjcwNjQyNTlaFw0yODAzMjYwNzQyNTlaMFMxCzAJBgNV
BAYTAkNOMSEwHwYDVQQKExhJbmZpbml0ZSBXaXNkb20gU29mdHdhcmUxITAfBgNV
BAMTGFlhbyBUZXN0IEludGVybWVkaWF0ZSBDQTB2MBAGByqGSM49AgEGBSuBBAAi
A2IABHG2U+9ScPK/NBfGW3jgg8fNVH/NfGcPOkypKHonsIad1fG4H+kUtEyyQTvP
4of6FO8FmnvyezMdtaEPlUxRLmYPW9dqsnCZswZasgQLOd5b+qxe4bFY86yla2Iq
HxWIyKNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD
VR0OBBYEFHoGH8BliDziOpSBraPs5+ehyWBMMB8GA1UdIwQYMBaAFB6XvPEQD+g1
yTpwyPj3Quwu9wuXMAoGCCqGSM49BAMDA2kAMGYCMQCkN/W+unUuHyP/2phruVv4
itASDUZfm3ZDGS450ixZO9OMQZ9t/dNv1HyfN0M9wCMCMQDoYKwveqllF7XvSPQp
fBfRbxsR+t8LpJqzNXMGgzUpKuZ/KLBAjnbZgwCCGCR1zN0=
-----END CERTIFICATE-----