Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
e6e98cd
feat: Oryx SDK regional distribution — pull SDKs from ACR
Apr 1, 2026
43067b3
feat: Add ACR-based SDK distribution with feature flag
Apr 1, 2026
56e8f6d
refactor: Simplify ExternalAcrSdkProvider - let LWASv2 handle image r…
Apr 1, 2026
b38884d
refactor: Remove script-based ACR publish (moved to AAPT-Antares-Oryx…
Apr 1, 2026
faa6b2d
fix: Default ACR SDK registry to oryxacr.azurecr.io
Apr 1, 2026
505580f
fix: Resolve StyleCop analyzer errors in ACR SDK provider files
Apr 1, 2026
3a88dfe
fix: Resolve StyleCop analyzer errors in ACR SDK provider files
Apr 1, 2026
78c75d3
latest pull
kumaraksh1 Apr 1, 2026
cf20ab6
Feature/oryx sdk acr distribution sdks resolver (#2842)
kumaraksh1 Apr 1, 2026
962a3a3
fix build and tests (#2843)
kumaraksh1 Apr 1, 2026
7d8e4ea
fix to fetch from acr (#2844)
kumaraksh1 Apr 1, 2026
ccafe60
Update version providers (#2845)
kumaraksh1 Apr 2, 2026
4f0262e
Refactor version providers (#2846)
kumaraksh1 Apr 2, 2026
0b24751
Fix acr version info (#2848)
kumaraksh1 Apr 2, 2026
061b3c9
Changes for php composer (#2849)
kumaraksh1 Apr 2, 2026
268a682
Clean dead code (#2850)
kumaraksh1 Apr 2, 2026
c2e1e23
Fix priroity in sdk resolver (#2851)
kumaraksh1 Apr 2, 2026
dd2367f
Fix Uts and version providers (#2852)
kumaraksh1 Apr 2, 2026
c427f24
ACR Sdk provider refactor (#2854)
kumaraksh1 Apr 2, 2026
f9de4e6
registryclient improvements
sarsharma Apr 3, 2026
7e429cb
Merge branch 'feature/oryx-sdk-acr-distribution' of https://github.co…
sarsharma Apr 3, 2026
8ae6264
fix build issue
sarsharma Apr 3, 2026
bda3623
Add changes foe external ACR provider (#2855)
kumaraksh1 Apr 3, 2026
04e1b11
Change flag name for external acr case (#2856)
kumaraksh1 Apr 3, 2026
77d9f99
Handle multiplatform (#2857)
kumaraksh1 Apr 3, 2026
6808271
Revert "Handle multiplatform (#2857)" (#2858)
kumaraksh1 Apr 3, 2026
476b64f
Disable external ACR for multiplatform (#2859)
kumaraksh1 Apr 3, 2026
dda3a96
Fix test case (#2860)
kumaraksh1 Apr 3, 2026
eb2f4e8
Refactor external acr provider (#2862)
kumaraksh1 Apr 3, 2026
69cd61e
update externalacrsdkprovider contract
sarsharma Apr 4, 2026
df51c58
Align ExternalAcrSdkProvider and ExternalAcrVersionProviderBase with …
Apr 4, 2026
8a56014
update logic for dotnet and default versions
sarsharma Apr 4, 2026
5d8b2f7
update logic for dotnet and default versions (#2864)
sarsharma Apr 4, 2026
aed87c7
Merge branch 'feature/oryx-sdk-acr-distribution' of https://github.co…
sarsharma Apr 4, 2026
03e68ed
Refactor code for new acr way (#2863)
kumaraksh1 Apr 4, 2026
1516468
nit fix (#2865)
kumaraksh1 Apr 4, 2026
4611ff7
Refactor ACR SDK provider to return tarball path
sarsharma Apr 4, 2026
e10bcf5
ACR SDK distribution: Refactor direct acr sdk fetching logic (#2866)
sarsharma Apr 4, 2026
1e804be
Merge branch 'feature/oryx-sdk-acr-distribution' of https://github.co…
sarsharma Apr 4, 2026
693727d
Cleanup startupscriptgen and refactor ACR SDK distribution constants
sarsharma Apr 4, 2026
6e2c252
ACR Sdk distribution: Cleanup startupscriptgenerator and fix image re…
sarsharma Apr 4, 2026
402f206
Merge branch 'feature/oryx-sdk-acr-distribution' of https://github.co…
sarsharma Apr 4, 2026
41991b1
Refactor ACR SDK provider methods to return boolean status and update…
sarsharma Apr 4, 2026
b7b98ee
Update version provider logic to check for external SDK provider option
sarsharma Apr 4, 2026
e839939
ACR Sdk distribution: Fix failure path for acr sdk fetching (#2868)
sarsharma Apr 4, 2026
ea20742
Update version provider fallback (#2872)
kumaraksh1 Apr 4, 2026
482a3d3
Update fallback logic for sdks (#2873)
kumaraksh1 Apr 4, 2026
0509648
Merge branch 'feature/oryx-sdk-acr-distribution' of https://github.co…
sarsharma Apr 4, 2026
c92c90b
version map fix
sarsharma Apr 4, 2026
bea56ef
fix externalacrprovider for dotnet
sarsharma Apr 4, 2026
f7d8970
ACR Sdk distribution: fix external ACR sdk provider for dotnet (#2874)
sarsharma Apr 4, 2026
82bbdc1
Feature/oryx sdk acr distribution fix phpand composer (#2875)
kumaraksh1 Apr 4, 2026
cf85f1f
Enhance OciRegistryClient to support anonymous token acquisition for …
sarsharma Apr 4, 2026
e65ab64
add logging
sarsharma Apr 4, 2026
d1f430e
Merge branch 'feature/oryx-sdk-acr-distribution' of https://github.co…
sarsharma Apr 4, 2026
5dffc25
Acr SDK Distribution: Add token for listing sdk images (#2876)
sarsharma Apr 4, 2026
25e09ff
fix build
sarsharma Apr 4, 2026
12679b1
Merge branch 'feature/oryx-sdk-acr-distribution' of https://github.co…
sarsharma Apr 4, 2026
82750e0
suppress auth header from logs
sarsharma Apr 4, 2026
6927662
fix socket paths
sarsharma Apr 5, 2026
b888008
Add a method to fetch all versions for a platform (#2877)
kumaraksh1 Apr 5, 2026
0ff88ac
fix fallback flow
sarsharma Apr 5, 2026
37b2f4f
Merge branch 'feature/oryx-sdk-acr-distribution' of https://github.co…
sarsharma Apr 5, 2026
6530647
logging fixes
sarsharma Apr 5, 2026
10b4488
logging fixes (#2878)
sarsharma Apr 5, 2026
e8338e7
fix tar extraction and add more logging
sarsharma Apr 5, 2026
f652350
Merge branch 'feature/oryx-sdk-acr-distribution' of https://github.co…
sarsharma Apr 5, 2026
81c204d
fix dotnet image pull
sarsharma Apr 5, 2026
ea1d124
handle gzip stream
sarsharma Apr 5, 2026
a23d473
fix php installationscript duplication
sarsharma Apr 5, 2026
6a035c6
ACR Sdk dist: Enhancements for cache management (#2889)
sarsharma Apr 6, 2026
1aee0e1
Feature/oryx sdk acr distribution pr review 1 (#2888)
kumaraksh1 Apr 6, 2026
f149c27
Fix UTs
kumaraksh1 Apr 7, 2026
2750adc
ACR SDK dist: Add tests, refactoring and some fixes (#2892)
sarsharma Apr 7, 2026
ac413ec
Fix composer logic (#2893)
kumaraksh1 Apr 7, 2026
f423409
fix build (#2894)
kumaraksh1 Apr 7, 2026
2f2b67d
Add .NET SDK versions and composerVersion to constants.yml
Apr 7, 2026
2847957
ACR SDK dist: Refactor version provider and bump up dependencies (#2895)
sarsharma Apr 7, 2026
0bad95a
ACR SDK dist: Additional test cases (#2896)
sarsharma Apr 7, 2026
73aafda
follow existing pattern for php composer, add more tests
sarsharma Apr 7, 2026
dd1484f
Revert "Add .NET SDK versions and composerVersion to constants.yml"
Apr 7, 2026
3e7b7ae
update comment
sarsharma Apr 7, 2026
52bc0e2
Add VERSIONS_TO_BUILD_OVERRIDE to force-build specific SDK versions (…
CodingIsBliss Apr 8, 2026
bf4bb4a
resolve comments
kumaraksh1 Apr 8, 2026
357df9a
nit
kumaraksh1 Apr 8, 2026
134eb16
fix comment
sarsharma Apr 8, 2026
6c24341
Merge branch 'feature/oryx-sdk-acr-distribution' of https://github.co…
sarsharma Apr 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions platforms/__common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,50 @@ getSdkFromImage() {
buildPlatform() {
local versionFile="$1"
local funcToCall="$2"

# When VERSIONS_TO_BUILD_OVERRIDE is set (comma-separated list of versions),
# only build those specific versions and skip blob existence checks entirely.
# This allows force-building specific SDK versions without rebuilding everything.
if [ -n "$VERSIONS_TO_BUILD_OVERRIDE" ]; then
echo "VERSIONS_TO_BUILD_OVERRIDE is set: $VERSIONS_TO_BUILD_OVERRIDE"
echo "Building only specified versions, skipping storage account checks."
export OVERWRITE_EXISTING_SDKS="true"

# Build a lookup set of requested versions
IFS=',' read -ra _requested_versions <<< "$VERSIONS_TO_BUILD_OVERRIDE"
declare -A _force_set
for _v in "${_requested_versions[@]}"; do
_v="$(echo "$_v" | xargs)"
[ -n "$_v" ] && _force_set["$_v"]=1
done

# Read the version file but only invoke the build function for matching versions.
# This preserves extra args (e.g. GPG keys, SHAs) that some platforms need.
while IFS= read -r VERSION_INFO || [[ -n $VERSION_INFO ]]; do
VERSION_INFO="$(echo -e "${VERSION_INFO}" | sed -e 's/^[[:space:]]*//')"
if [ -z "$VERSION_INFO" ] || [[ $VERSION_INFO = \#* ]]; then
continue
fi

IFS=',' read -ra VERSION_INFO_PARTS <<< "$VERSION_INFO"
lineVersion="$(echo -e "${VERSION_INFO_PARTS[0]}" | sed -e 's/^[[:space:]]*//')"

if [ -z "${_force_set[$lineVersion]:-}" ]; then
continue
fi

echo "Force-building version: $lineVersion"
versionArgs=()
for arg in "${VERSION_INFO_PARTS[@]}"; do
arg="$(echo -e "${arg}" | sed -e 's/^[[:space:]]*//')"
versionArgs+=("$arg")
done

$funcToCall "${versionArgs[@]}"
done < "$versionFile"
return
fi

while IFS= read -r VERSION_INFO || [[ -n $VERSION_INFO ]]
do
# remove all whitespace before first character
Expand Down
2 changes: 2 additions & 0 deletions platforms/nodejs/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ ARG OS_FLAVOR
FROM mcr.microsoft.com/mirror/docker/library/buildpack-deps:${OS_FLAVOR}
ARG OS_FLAVOR
ENV OS_FLAVOR=$OS_FLAVOR
ARG VERSIONS_TO_BUILD_OVERRIDE=""
ENV VERSIONS_TO_BUILD_OVERRIDE=$VERSIONS_TO_BUILD_OVERRIDE

RUN apt-get update \
&& apt-get install -y --no-install-recommends \
Expand Down
2 changes: 2 additions & 0 deletions platforms/php/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ ARG OS_FLAVOR
FROM mcr.microsoft.com/mirror/docker/library/buildpack-deps:${OS_FLAVOR} AS php-buildpack-prereqs
ARG OS_FLAVOR
ENV OS_FLAVOR=$OS_FLAVOR
ARG VERSIONS_TO_BUILD_OVERRIDE=""
ENV VERSIONS_TO_BUILD_OVERRIDE=$VERSIONS_TO_BUILD_OVERRIDE
COPY platforms/php/prereqs /php
COPY platforms/php/prereqs/build.sh /tmp/
COPY images/receiveGpgKeys.sh /tmp/receiveGpgKeys.sh
Expand Down
2 changes: 2 additions & 0 deletions platforms/php/composer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ ARG OS_FLAVOR
FROM mcr.microsoft.com/mirror/docker/library/buildpack-deps:${OS_FLAVOR} AS php-buildpack-prereqs
ARG OS_FLAVOR
ENV OS_FLAVOR=$OS_FLAVOR
ARG VERSIONS_TO_BUILD_OVERRIDE=""
ENV VERSIONS_TO_BUILD_OVERRIDE=$VERSIONS_TO_BUILD_OVERRIDE
COPY platforms/php/prereqs /php
# COPY build/__phpVersions.sh /php/
COPY platforms/php/prereqs/build.sh /tmp/
Expand Down
2 changes: 2 additions & 0 deletions platforms/python/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ ARG OS_FLAVOR
FROM mcr.microsoft.com/mirror/docker/library/buildpack-deps:${OS_FLAVOR}
ARG OS_FLAVOR
ENV OS_FLAVOR=$OS_FLAVOR
ARG VERSIONS_TO_BUILD_OVERRIDE=""
ENV VERSIONS_TO_BUILD_OVERRIDE=$VERSIONS_TO_BUILD_OVERRIDE

# COPY build/__pythonVersions.sh /tmp/

Expand Down
21 changes: 21 additions & 0 deletions src/BuildScriptGenerator.Common/SdkImageRepositoryHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// --------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
// --------------------------------------------------------------------------------------------

namespace Microsoft.Oryx.BuildScriptGenerator.Common
{
public static class SdkImageRepositoryHelper
{
/// <summary>
/// Maps a platform name to its OCI SDK image repository path.
/// e.g. "nodejs" → "oryx/nodejs-sdk", "php" → "oryx/php-sdk".
/// Final image ref: mcr.microsoft.com/oryx/nodejs-sdk:bookworm-20.20.2
/// </summary>
public static string GetSdkImageRepository(string platformName, string prefix = null)
{
prefix = string.IsNullOrEmpty(prefix) ? SdkStorageConstants.DefaultAcrSdkRepositoryPrefix : prefix;
return $"{prefix}/{platformName}-sdk";
}
}
}
4 changes: 4 additions & 0 deletions src/BuildScriptGenerator.Common/SdkStorageConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,9 @@ public static class SdkStorageConstants
public const string DotnetRuntimeVersionMetadataName = "Dotnet_runtime_version";
public const string LegacyDotnetRuntimeVersionMetadataName = "Runtime_version";
public const string OsTypeMetadataName = "Os_type";

// OCI image based SDK distribution constants
public const string DefaultAcrSdkRegistryUrl = "https://mcr.microsoft.com";
public const string DefaultAcrSdkRepositoryPrefix = "oryx";
}
}
212 changes: 212 additions & 0 deletions src/BuildScriptGenerator/AcrSdkProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
// --------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
// --------------------------------------------------------------------------------------------

using System;
using System.Formats.Tar;
using System.IO;
using System.IO.Compression;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Oryx.BuildScriptGenerator.Common;

namespace Microsoft.Oryx.BuildScriptGenerator
{
/// <summary>
/// Fetches SDK tarballs directly from an OCI container registry.
/// SDK images are single-layer <c>FROM scratch</c> images containing a single
/// <c>.tar.gz</c> SDK file. The OCI layer blob is a tar archive of the image
/// filesystem, so this provider downloads the layer, extracts the inner SDK
/// tarball from it, and caches it locally.
/// </summary>
/// <remarks>
/// Makes direct HTTP calls to the registry (no Unix socket).
/// See <see cref="ExternalAcrSdkProvider"/> for the socket-based variant.
/// </remarks>
public class AcrSdkProvider : IAcrSdkProvider
{
private readonly ILogger<AcrSdkProvider> logger;
private readonly IStandardOutputWriter outputWriter;
private readonly BuildScriptGeneratorOptions options;
private readonly OciRegistryClient ociClient;

public AcrSdkProvider(
IStandardOutputWriter outputWriter,
ILogger<AcrSdkProvider> logger,
IOptions<BuildScriptGeneratorOptions> options,
OciRegistryClient ociClient)
{
this.logger = logger;
this.outputWriter = outputWriter;
this.options = options.Value;
this.ociClient = ociClient;
}

/// <inheritdoc/>
public async Task<bool> RequestSdkFromAcrAsync(string platformName, string version, string debianFlavor, string runtimeVersion = null)
{
if (string.IsNullOrEmpty(platformName))
{
throw new ArgumentException("Platform name cannot be null or empty.", nameof(platformName));
}

if (string.IsNullOrEmpty(version))
{
throw new ArgumentException("Version cannot be null or empty.", nameof(version));
}

if (string.IsNullOrEmpty(debianFlavor))
{
debianFlavor = this.options.DebianFlavor ?? "bookworm";
}

var repository = SdkImageRepositoryHelper.GetSdkImageRepository(platformName, this.options.OryxAcrSdkRepositoryPrefix);
var tag = string.IsNullOrEmpty(runtimeVersion)
? $"{debianFlavor}-{version}"
: $"{debianFlavor}-{version}_{runtimeVersion}";
var blobName = $"{platformName}-{debianFlavor}-{version}.tar.gz";

this.logger.LogInformation(
"Requesting SDK from ACR: {Repository}:{Tag}",
repository,
tag);
this.outputWriter.WriteLine(
$"Requesting SDK from ACR: {repository}:{tag}");

// Download to the writable dynamic install directory, NOT /var/OryxSdks (read-only external mount).
var downloadDir = Path.Combine(this.options.DynamicInstallRootDir, platformName);
var tarballPath = Path.Combine(downloadDir, blobName);
var digestPath = Path.Combine(downloadDir, $".{blobName}.digest");

try
{
// Get image manifest
var remoteDigest = await this.ociClient.GetManifestDigestAsync(repository, tag);

// Check if cached tarball is still fresh
if (File.Exists(tarballPath) && File.Exists(digestPath) && remoteDigest != null)
{
var localDigest = File.ReadAllText(digestPath).Trim();
if (string.Equals(localDigest, remoteDigest, StringComparison.OrdinalIgnoreCase))
{
this.logger.LogInformation(
"SDK cache is fresh (digest match): {FilePath}",
tarballPath);
this.outputWriter.WriteLine(
$"SDK tarball already cached and fresh at {tarballPath}");
return true;
}

this.logger.LogInformation(
"SDK cache is stale (digest mismatch). Re-downloading.");
}

// Get manifest → extract single layer digest
var manifest = await this.ociClient.GetManifestAsync(repository, tag);
var layerDigest = OciRegistryClient.GetFirstLayerDigest(manifest);

if (string.IsNullOrEmpty(layerDigest))
{
this.logger.LogWarning(
"No layer found in manifest for {Repository}:{Tag}",
repository,
tag);
this.outputWriter.WriteLine($"No layer found in ACR manifest for {platformName} {version}.");
return false;
}

Directory.CreateDirectory(downloadDir);

// 2. Download the OCI layer blob to a temp file.
// The layer is a tar archive of the image filesystem (not the SDK tarball itself).
var layerTempPath = Path.Combine(downloadDir, $".layer-{Guid.NewGuid():N}.tmp");
try
{
var downloadSuccess = await this.ociClient.DownloadLayerBlobAsync(
repository,
layerDigest,
layerTempPath);

if (!downloadSuccess)
{
this.logger.LogWarning(
"ACR SDK pull failed digest verification: {Repository}:{Tag}",
repository,
tag);
this.outputWriter.WriteLine(
$"Failed to pull SDK from ACR (digest mismatch): {platformName} {version}");
return false;
}

// 3. Extract the inner SDK .tar.gz from the layer tar.
// The image is FROM scratch with a single COPY of the SDK tarball,
// so the layer contains the .tar.gz as a top-level entry.
this.ExtractFileFromTar(layerTempPath, tarballPath, blobName);
}
finally
{
// Always clean up the temporary layer file
if (File.Exists(layerTempPath))
{
File.Delete(layerTempPath);
}
}

this.logger.LogInformation(
"Successfully pulled SDK from ACR: {Repository}:{Tag} → {FilePath}",
repository,
tag,
tarballPath);
this.outputWriter.WriteLine(
$"Successfully pulled SDK from ACR: {platformName} {version}");

// Write manifest digest sidecar for future freshness checks
if (!string.IsNullOrEmpty(remoteDigest))
{
File.WriteAllText(digestPath, remoteDigest);
}

return true;
}
catch (Exception ex)
{
this.logger.LogError(
ex,
"Error pulling SDK from ACR: {Repository}:{Tag}",
repository,
tag);
this.outputWriter.WriteLine(
$"Error pulling SDK from ACR: {platformName} {version}: {ex.Message}");
return false;
}
}

/// <summary>
/// Extracts the expected SDK .tar.gz file from an OCI layer tar archive.
/// OCI layers use media type "application/vnd.docker.image.rootfs.diff.tar.gzip",
/// so the blob must be decompressed before reading tar entries.
/// </summary>
private void ExtractFileFromTar(string layerPath, string outputPath, string expectedFileName)
{
using (var stream = File.OpenRead(layerPath))
using (var gzipStream = new GZipStream(stream, CompressionMode.Decompress))
using (var tarReader = new TarReader(gzipStream))
{
TarEntry entry;
while ((entry = tarReader.GetNextEntry()) != null)
{
var name = entry.Name.TrimStart('.', '/');
if (entry.DataStream != null && name.Equals(expectedFileName, StringComparison.OrdinalIgnoreCase))
{
entry.ExtractToFile(outputPath, overwrite: true);
return;
}
}
}

throw new InvalidOperationException($"Expected entry '{expectedFileName}' not found in OCI layer: {layerPath}");
}
}
}
Loading
Loading