Repository navigation
149 lines (144 loc) · 6.88 KB
/
Copy pathpackages.yml
File metadata and controls
149 lines (144 loc) · 6.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
name: Function ZIPs
on:
pull_request:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: function-zips-${{ github.ref }}
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '22.x'
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.11'
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
dotnet-version: '8.0.x'
- name: Test JavaScript
working-directory: javascript
run: |
npm ci --ignore-scripts --no-audit --no-fund
npm test
- name: Test Python
working-directory: python
run: |
python -m pip install -r requirements.txt pytest
python -m pytest tests
- name: Test .NET
run: dotnet test dotnet/tests/Epp.Otp.Tests.csproj
- name: Build ZIPs
shell: pwsh
run: |
./package-javascript.ps1
./package-dotnet.ps1
./package-python.ps1
- name: Verify existing ZIPs are never overwritten
shell: pwsh
run: |
$packages = @{
'package-javascript.ps1' = 'artifacts/epp-javascript.zip'
'package-dotnet.ps1' = 'artifacts/epp-dotnet-source.zip'
'package-python.ps1' = 'artifacts/epp-python-source.zip'
}
foreach ($script in ($packages.Keys | Sort-Object)) {
$archive = (Resolve-Path -LiteralPath $packages[$script]).Path
$before = (Get-FileHash -LiteralPath $archive -Algorithm SHA256).Hash
$rejected = $false
try {
& (Join-Path $PWD $script) -OutputPath $archive
} catch {
if (-not $_.Exception.Message.StartsWith('Output already exists:')) { throw }
$rejected = $true
}
if (-not $rejected) { throw "$script did not reject an existing archive" }
if ((Get-FileHash -LiteralPath $archive -Algorithm SHA256).Hash -ne $before) {
throw "$script changed the existing archive"
}
Write-Host "$script rejected the existing output; SHA256 unchanged."
}
- name: Verify ZIPs and write checksums
shell: pwsh
run: |
$required = @{
'epp-javascript.zip' = @('host.json', 'src/functions/SendOtp.js', 'node_modules/@azure/functions/package.json')
'epp-dotnet-source.zip' = @('host.json', 'dotnet.csproj', 'Program.cs', 'Functions/SendOtp.cs', 'Src/PhoneProviderBase.cs')
'epp-python-source.zip' = @('host.json', 'function_app.py', 'requirements.txt', 'src/jwe.py', 'src/provider.py')
}
$checksums = foreach ($name in ($required.Keys | Sort-Object)) {
$path = Join-Path 'artifacts' $name
$zip = [IO.Compression.ZipFile]::OpenRead((Resolve-Path $path))
try {
$entries = @($zip.Entries.FullName)
foreach ($file in $required[$name]) {
if ($file -notin $entries) { throw "Missing $file in $name" }
}
if ($entries -match '(^|/)(local\.settings[^/]*|\.env[^/]*|\.git|\.venv|__pycache__)(/|$)|\.(pem|pfx|p12|key|publishsettings|pubxml)$') {
throw "Private files in $name"
}
if ($name -eq 'epp-dotnet-source.zip' -and
($entries -match '(^|/)(bin|obj|tests?|\.azurefunctions)(/|$)|\.(dll|exe|pdb|deps\.json|runtimeconfig\.json)$|(^|/)(functions\.metadata|worker\.config\.json)$')) {
throw 'Build output or tests found in .NET source ZIP'
}
} finally { $zip.Dispose() }
'{0} {1}' -f (Get-FileHash $path -Algorithm SHA256).Hash.ToLowerInvariant(), $name
}
$checksums | Set-Content artifacts/SHA256SUMS.txt -Encoding utf8
- name: Verify .NET source ZIP can be published by customers
shell: pwsh
run: |
$temporary = Join-Path ([IO.Path]::GetTempPath()) ('epp-source-check-' + [guid]::NewGuid().ToString('N'))
try {
$source = Join-Path $temporary 'source'
$publish = Join-Path $temporary 'publish'
[IO.Compression.ZipFile]::ExtractToDirectory((Resolve-Path 'artifacts/epp-dotnet-source.zip'), $source)
dotnet publish (Join-Path $source 'dotnet.csproj') --configuration Release --output $publish --verbosity minimal
if ($LASTEXITCODE -ne 0) { throw 'Extracted .NET source could not be published' }
foreach ($file in @('host.json', 'dotnet.dll', 'functions.metadata', 'worker.config.json', '.azurefunctions')) {
if (-not (Test-Path -LiteralPath (Join-Path $publish $file))) { throw "Missing customer publish output: $file" }
}
} finally {
if (Test-Path -LiteralPath $temporary) { Remove-Item -LiteralPath $temporary -Recurse -Force }
}
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: function-zips
path: |
artifacts/epp-javascript.zip
artifacts/epp-dotnet-source.zip
artifacts/epp-python-source.zip
artifacts/SHA256SUMS.txt
if-no-files-found: error
retention-days: 14
publish:
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: function-zips
path: artifacts
- name: Publish versioned ZIP downloads
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
COMMIT_SHA: ${{ github.sha }}
RUN_NUMBER: ${{ github.run_number }}
RUN_ATTEMPT: ${{ github.run_attempt }}
run: |
tag="epp-packages-${RUN_NUMBER}-${RUN_ATTEMPT}"
gh release create "$tag" artifacts/*.zip artifacts/SHA256SUMS.txt \
--target "$COMMIT_SHA" --title "EPP Function ZIPs ${RUN_NUMBER}.${RUN_ATTEMPT}" \
--latest \
--notes "Packaged and tested from commit ${COMMIT_SHA}. Download one language ZIP and verify it against SHA256SUMS.txt. JavaScript includes production dependencies. .NET contains project and C# source only: extract and build/publish the project before deployment. Python is a source ZIP requiring Azure remote build on Linux. Neither source ZIP is a direct run-from-package artifact. Configure runtime, app settings, Key Vault access, and Easy Auth separately. No cloud deployment or live provider verification is performed."