Public Access
Give the API an image, and unbreak the restore that had to run first
registry-docker.dodotech.cloud/dodotech/dodossh-api, built and pushed by a third ci job
that needs the first. Gating on the tests costs a few minutes on every main commit and buys
the only thing worth having here: an image is not an artefact somebody inspects before
using it, so a red commit must not be able to produce one. Pull requests build the image
and stop, which is where a broken Dockerfile should be found.
Tags are :sha-<short> on every build, :main on main, and for a v* tag :1.2.3, :1.2 and
:latest — the last two only when the version has no prerelease suffix, since v1.3.0-rc1
sorts above v1.2.9 and would otherwise walk :latest onto somebody's server. Only sha- is
immutable, and it is the one to pin a deployment to.
No docker/* actions. The build is single-architecture, so it needs the daemon this runner
already has for the Testcontainers suites and nothing else — no buildx, no QEMU, and no
third-party action whose SHA has to be audited and re-pinned. Step outputs and secrets
reach the shell through env rather than ${{ }} interpolation, because a git tag may contain
a semicolon and interpolation is textual substitution performed before the shell parses the
line.
The image is chiseled: no shell, no package manager, uid 1654. Affordable because
Directory.Build.props already sets InvariantGlobalization, so the ICU and tzdata a normal
base carries are exactly what this product decided not to use. The cost is stated in the
Dockerfile rather than hidden — there is no HEALTHCHECK, because there is nothing to run
one with, and /healthz/ready is anonymous precisely so the orchestrator can ask instead.
Nothing migrates the schema from inside the container either; readiness fails while a
migration is pending and names it, which is the design.
And the restore that all of this depends on did not work. 7a3a521 committed lock files
carrying a net10.0/android-arm64 section into fourteen projects — written there by the
Android head's -p:RuntimeIdentifier=android-arm64 packaging build, which restores the
shared projects with a RID and updates their lock files as a side effect. Any restore
without that RID then fails NU1004 in locked mode, which is every other build there is:
`dotnet restore DodoSSH.slnx --locked-mode` has been failing for eleven projects on a clean
checkout of main since that commit. The sections are removed here and nothing else changed
— deletions only, ILLink.Tasks stays at 10.0.10.
Verified: the solution restores in locked mode, the image builds, and it runs. /healthz/live
answers 200 and /healthz/ready answers 503 naming the database it cannot reach, from a
67 MB image as uid 1654, configured entirely through DODOSSH_-prefixed variables.
The Android head's own lock file still carries the RID and is untouched, because that job
restores it separately and is outside DodoSSH.slnx. Whether its packaging step re-dirties
these fourteen on every CI run is worth a look; it is the same mechanism.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
# The build context for src/DodoSSH.Api/Dockerfile is the repository root, because central
|
||||
# package management puts Directory.Packages.props there. That makes this file matter more
|
||||
# than it usually does: without it the context is the whole working tree, including every
|
||||
# bin/ and obj/ directory and the Android head's build output.
|
||||
#
|
||||
# Excluding obj/ is not only about size. A host obj/ carries project.assets.json and the
|
||||
# generated .nuget.g.props naming absolute host paths; copied into the image it overrides
|
||||
# the restore that just ran inside it, and the failure surfaces as packages "not found"
|
||||
# that are plainly present.
|
||||
|
||||
**/bin/
|
||||
**/obj/
|
||||
artifacts/
|
||||
.git/
|
||||
.github/
|
||||
.gitea/
|
||||
.idea/
|
||||
.vs/
|
||||
.vscode/
|
||||
|
||||
# No project outside the API's reference closure contributes to this image. Listing them
|
||||
# keeps a context change from silently invalidating the COPY src/ layer on every commit to
|
||||
# a head this image does not contain.
|
||||
src/DodoSSH.Client.*/
|
||||
tests/
|
||||
docs/
|
||||
deploy/
|
||||
|
||||
*.md
|
||||
*.user
|
||||
*.binlog
|
||||
Dockerfile*
|
||||
.dockerignore
|
||||
@@ -3,6 +3,10 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
# Release tags run the whole workflow, not only the image job that gates on it. A tag
|
||||
# is the one build nobody is watching, so it is the last place to take the tests on
|
||||
# trust.
|
||||
tags: ['v*']
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
@@ -100,3 +104,122 @@ jobs:
|
||||
dotnet build src/DodoSSH.Client.Android/DodoSSH.Client.Android.csproj
|
||||
--no-restore --configuration Release
|
||||
-t:SignAndroidPackage -p:RuntimeIdentifier=android-arm64
|
||||
|
||||
image:
|
||||
name: api image
|
||||
# Gated on the tests rather than parallel with them, which costs a few minutes of wall
|
||||
# clock on every main commit and buys the thing worth having: no image reaches the
|
||||
# registry from a commit whose tests were red. An image is not a build artefact anyone
|
||||
# inspects — it is the thing that gets deployed.
|
||||
needs: [build]
|
||||
runs-on: [linux]
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
# No docker/* actions here, deliberately. The build is single-architecture, so it
|
||||
# needs the daemon this runner already has for the Testcontainers suites and nothing
|
||||
# else — no buildx plugin, no QEMU, and no third-party action whose SHA has to be
|
||||
# audited and re-pinned. Adding linux/arm64 later is where that trade changes.
|
||||
- name: work out the tags
|
||||
id: tags
|
||||
env:
|
||||
REGISTRY: registry-docker.dodotech.cloud
|
||||
IMAGE: dodotech/dodossh-api
|
||||
run: |
|
||||
set -euo pipefail
|
||||
repo="$REGISTRY/$IMAGE"
|
||||
short="$(git rev-parse --short HEAD)"
|
||||
|
||||
# sha- prefixed, because a bare hex tag is ambiguous with a digest to both a human
|
||||
# and a fair amount of tooling. This one is on every build and never moves, which
|
||||
# makes it the only tag safe to pin a deployment to.
|
||||
tags="$repo:sha-$short"
|
||||
version="$short"
|
||||
|
||||
case "$GITHUB_REF" in
|
||||
refs/tags/v*)
|
||||
v="${GITHUB_REF#refs/tags/v}"
|
||||
version="$v"
|
||||
tags="$tags $repo:$v"
|
||||
# The moving major.minor tag and :latest, but only for a release proper.
|
||||
# v1.3.0-rc1 sorts after v1.2.9 and would otherwise take :latest with it,
|
||||
# which is how a release candidate ends up on somebody's server.
|
||||
case "$v" in
|
||||
*-*) ;;
|
||||
*)
|
||||
tags="$tags $repo:${v%.*}"
|
||||
tags="$tags $repo:latest"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
refs/heads/main)
|
||||
tags="$tags $repo:main"
|
||||
version="main-$short"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "tags=$tags" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||
echo "created=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT"
|
||||
echo "Tagging: $tags"
|
||||
|
||||
# Every value from a step output or the event goes through env rather than being
|
||||
# interpolated into the script text. A git tag may contain a semicolon, and
|
||||
# `${{ }}` is a textual substitution performed before the shell ever sees the line —
|
||||
# so an interpolated tag name is a command the workflow agreed to run.
|
||||
- name: build the image
|
||||
env:
|
||||
TAGS: ${{ steps.tags.outputs.tags }}
|
||||
VERSION: ${{ steps.tags.outputs.version }}
|
||||
REVISION: ${{ github.sha }}
|
||||
CREATED: ${{ steps.tags.outputs.created }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
args=()
|
||||
for tag in $TAGS; do
|
||||
args+=(--tag "$tag")
|
||||
done
|
||||
# --pull rather than whatever the runner happens to have cached: the base images
|
||||
# are floating tags, and a runner that has held aspnet:10.0-noble-chiseled for a
|
||||
# month is a month of unapplied CVE fixes shipping in every image built on it.
|
||||
docker build \
|
||||
--pull \
|
||||
--file src/DodoSSH.Api/Dockerfile \
|
||||
--build-arg "VERSION=$VERSION" \
|
||||
--build-arg "REVISION=$REVISION" \
|
||||
--build-arg "CREATED=$CREATED" \
|
||||
"${args[@]}" \
|
||||
.
|
||||
|
||||
# Everything above runs on a pull request too. Building a fork's Dockerfile is safe —
|
||||
# nothing is pushed and no credential is in scope — and it means a change that breaks
|
||||
# the image fails on the PR rather than on main. Only these last two steps are held
|
||||
# back, and the condition is on the event rather than on the branch so that a PR
|
||||
# targeting main cannot reach them.
|
||||
- name: log in to the registry
|
||||
if: github.event_name != 'pull_request'
|
||||
env:
|
||||
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
|
||||
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
printf '%s' "$REGISTRY_PASSWORD" \
|
||||
| docker login registry-docker.dodotech.cloud \
|
||||
--username "$REGISTRY_USERNAME" --password-stdin
|
||||
|
||||
- name: push
|
||||
if: github.event_name != 'pull_request'
|
||||
env:
|
||||
TAGS: ${{ steps.tags.outputs.tags }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
for tag in $TAGS; do
|
||||
docker push "$tag"
|
||||
done
|
||||
|
||||
# The daemon is shared with every other job on this runner, and a credential left in
|
||||
# ~/.docker/config.json outlives the job that created it. always(), so a failed push
|
||||
# does not leave it behind.
|
||||
- name: log out
|
||||
if: always() && github.event_name != 'pull_request'
|
||||
run: docker logout registry-docker.dodotech.cloud
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
# The API image. Built from the repository root, not from this directory:
|
||||
#
|
||||
# docker build -f src/DodoSSH.Api/Dockerfile .
|
||||
#
|
||||
# Directory.Build.props, Directory.Packages.props, NuGet.config and global.json all sit at
|
||||
# the root and all four are load-bearing here — central package management means a csproj
|
||||
# alone does not name a single version, and a build that cannot see them resolves nothing.
|
||||
|
||||
# ---------------------------------------------------------------------------------------
|
||||
# Build
|
||||
# ---------------------------------------------------------------------------------------
|
||||
FROM mcr.microsoft.com/dotnet/sdk:10.0-noble AS build
|
||||
|
||||
# Reproducible builds. Directory.Build.props turns ContinuousIntegrationBuild on when this
|
||||
# is set, which is what normalises the source paths baked into the PDBs — without it two
|
||||
# builds of the same commit differ by the directory they happened in.
|
||||
ENV CI=true \
|
||||
DOTNET_NOLOGO=true \
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT=true \
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
# The manifests first, and only the manifests. This layer is what makes an ordinary code
|
||||
# change a ten-second rebuild instead of a full package restore: it is invalidated by a
|
||||
# dependency change and by nothing else. Every project in DodoSSH.Api's reference closure
|
||||
# has to be here — restore walks ProjectReference, and a missing csproj fails the graph
|
||||
# rather than skipping a node.
|
||||
COPY global.json NuGet.config Directory.Build.props Directory.Packages.props ./
|
||||
COPY src/DodoSSH.Api/DodoSSH.Api.csproj src/DodoSSH.Api/
|
||||
COPY src/DodoSSH.Api/packages.lock.json src/DodoSSH.Api/
|
||||
COPY src/DodoSSH.Contracts/DodoSSH.Contracts.csproj src/DodoSSH.Contracts/
|
||||
COPY src/DodoSSH.Contracts/packages.lock.json src/DodoSSH.Contracts/
|
||||
COPY src/DodoSSH.Crypto/DodoSSH.Crypto.csproj src/DodoSSH.Crypto/
|
||||
COPY src/DodoSSH.Crypto/packages.lock.json src/DodoSSH.Crypto/
|
||||
COPY src/DodoSSH.Domain/DodoSSH.Domain.csproj src/DodoSSH.Domain/
|
||||
COPY src/DodoSSH.Domain/packages.lock.json src/DodoSSH.Domain/
|
||||
COPY src/DodoSSH.Infrastructure/DodoSSH.Infrastructure.csproj src/DodoSSH.Infrastructure/
|
||||
COPY src/DodoSSH.Infrastructure/packages.lock.json src/DodoSSH.Infrastructure/
|
||||
|
||||
# Locked mode here for the same reason CI uses it: the lock files are committed, so a
|
||||
# dependency that changed without its lock file being reviewed fails the build rather than
|
||||
# quietly shipping. An image is the one place that matters most.
|
||||
RUN dotnet restore src/DodoSSH.Api/DodoSSH.Api.csproj --locked-mode
|
||||
|
||||
# BannedSymbols.txt is an AdditionalFiles entry in Directory.Build.props. Without it the
|
||||
# BannedApiAnalyzers rules silently pass, and with TreatWarningsAsErrors the whole point of
|
||||
# the list is that it fails a build — so its absence would be invisible in exactly the way
|
||||
# it is meant to prevent.
|
||||
COPY BannedSymbols.txt .editorconfig ./
|
||||
COPY src/ src/
|
||||
|
||||
RUN dotnet publish src/DodoSSH.Api/DodoSSH.Api.csproj \
|
||||
--no-restore \
|
||||
--configuration Release \
|
||||
--output /app \
|
||||
-p:UseAppHost=false
|
||||
|
||||
# ---------------------------------------------------------------------------------------
|
||||
# Runtime
|
||||
# ---------------------------------------------------------------------------------------
|
||||
#
|
||||
# Chiseled: no shell, no package manager, no libc utilities, and a non-root user (uid 1654)
|
||||
# already set by the base image. That closes off `docker exec sh` on a process that holds a
|
||||
# database connection and the cursor signing key, and it is affordable here specifically
|
||||
# because Directory.Build.props sets InvariantGlobalization — the ICU and tzdata a normal
|
||||
# base carries are exactly what this product has already decided it does not use.
|
||||
#
|
||||
# The cost is real and worth stating: there is no HEALTHCHECK below, because there is no
|
||||
# curl and nothing to run one with. The health endpoints exist and are anonymous —
|
||||
# /healthz/live, /healthz/ready, /healthz/startup — so the probe belongs in whatever runs
|
||||
# the container. Readiness is not decoration on this API: it fails while an EF migration is
|
||||
# pending and names the one it is waiting for, which is the intended way to discover that a
|
||||
# deployment shipped ahead of its schema.
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled AS final
|
||||
|
||||
# Passed by CI; see .github/workflows/ci.yml. Declared with empty defaults so a local
|
||||
# `docker build` with no arguments still succeeds.
|
||||
ARG VERSION=""
|
||||
ARG REVISION=""
|
||||
ARG CREATED=""
|
||||
|
||||
LABEL org.opencontainers.image.title="DodoSSH API" \
|
||||
org.opencontainers.image.description="DodoSSH server: sync, identity, teams and relay authorization." \
|
||||
org.opencontainers.image.vendor="DodoTech" \
|
||||
org.opencontainers.image.licenses="MIT" \
|
||||
org.opencontainers.image.source="https://git.dodotech.cloud/DodoTech/DodoSSH" \
|
||||
org.opencontainers.image.version="${VERSION}" \
|
||||
org.opencontainers.image.revision="${REVISION}" \
|
||||
org.opencontainers.image.created="${CREATED}"
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=build /app .
|
||||
|
||||
# 8080 is the .NET container default (ASPNETCORE_HTTP_PORTS in the base image), and plain
|
||||
# HTTP is deliberate: Program.cs has no UseHttpsRedirection because the API is always behind
|
||||
# a proxy that terminates TLS, and redirecting from here would loop.
|
||||
EXPOSE 8080
|
||||
|
||||
# Configuration reaches the process two ways, both already wired in Program.cs: environment
|
||||
# variables prefixed DODOSSH_, and files under /run/secrets for anything that should not be
|
||||
# readable in `docker inspect`. The three the process will not start or run correctly
|
||||
# without are DODOSSH_ConnectionStrings__Postgres, DODOSSH_Oidc__Authority and — on more
|
||||
# than one node — DODOSSH_Sync__CursorSigningKey.
|
||||
#
|
||||
# Nothing migrates the database from in here. That is the API's own design: it fails
|
||||
# /healthz/ready while a migration is pending and names it, so the schema is applied by
|
||||
# `dotnet ef database update` alongside the deployment rather than by a racing container.
|
||||
ENTRYPOINT ["dotnet", "DodoSSH.Api.dll"]
|
||||
@@ -41,14 +41,6 @@
|
||||
"libsodium": "[1.0.22, 1.0.23)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"net10.0/android-arm64": {
|
||||
"libsodium": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.0.22, )",
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "KPD9SloJFclrsjnhABu7dzWrcyYkwPbvx5l1gRSPAX/0n+OBtSiVCKtGFv4n+ecWUHU0tCG9LSSwoZZx673zBQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@
|
||||
"resolved": "5.6.0",
|
||||
"contentHash": "Kcobt3pnOdO0A+6CKiMHZdTEluJpsfxiV20axtZdmfBQnDmiWTKPJADlgAfdTuKNAnVarrkJa0UEGwuOo91muw=="
|
||||
}
|
||||
},
|
||||
"net10.0/android-arm64": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@
|
||||
"resolved": "5.6.0",
|
||||
"contentHash": "Kcobt3pnOdO0A+6CKiMHZdTEluJpsfxiV20axtZdmfBQnDmiWTKPJADlgAfdTuKNAnVarrkJa0UEGwuOo91muw=="
|
||||
}
|
||||
},
|
||||
"net10.0/android-arm64": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
"dodossh.client.domain": {
|
||||
"type": "Project"
|
||||
}
|
||||
},
|
||||
"net10.0/android-arm64": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,14 +83,6 @@
|
||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"net10.0/android-arm64": {
|
||||
"libsodium": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.0.22, )",
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "KPD9SloJFclrsjnhABu7dzWrcyYkwPbvx5l1gRSPAX/0n+OBtSiVCKtGFv4n+ecWUHU0tCG9LSSwoZZx673zBQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -291,20 +291,6 @@
|
||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"net10.0/android-arm64": {
|
||||
"libsodium": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.0.22, )",
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "KPD9SloJFclrsjnhABu7dzWrcyYkwPbvx5l1gRSPAX/0n+OBtSiVCKtGFv4n+ecWUHU0tCG9LSSwoZZx673zBQ=="
|
||||
},
|
||||
"SQLitePCLRaw.lib.e_sqlite3": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.1.12, )",
|
||||
"resolved": "2.1.12",
|
||||
"contentHash": "fWi8Dbknuhgg72fWinIdjXVaqO1hHL4YBBwVLnr7e1c9TAZwJ0QE38j9syW1hwx6HaqEVTwI+O07WPdZn8Rp0w=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -371,20 +371,6 @@
|
||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"net10.0/android-arm64": {
|
||||
"libsodium": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.0.22, )",
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "KPD9SloJFclrsjnhABu7dzWrcyYkwPbvx5l1gRSPAX/0n+OBtSiVCKtGFv4n+ecWUHU0tCG9LSSwoZZx673zBQ=="
|
||||
},
|
||||
"SQLitePCLRaw.lib.e_sqlite3": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.1.12, )",
|
||||
"resolved": "2.1.12",
|
||||
"contentHash": "fWi8Dbknuhgg72fWinIdjXVaqO1hHL4YBBwVLnr7e1c9TAZwJ0QE38j9syW1hwx6HaqEVTwI+O07WPdZn8Rp0w=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,14 +58,6 @@
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "KPD9SloJFclrsjnhABu7dzWrcyYkwPbvx5l1gRSPAX/0n+OBtSiVCKtGFv4n+ecWUHU0tCG9LSSwoZZx673zBQ=="
|
||||
}
|
||||
},
|
||||
"net10.0/android-arm64": {
|
||||
"libsodium": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.0.22, )",
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "KPD9SloJFclrsjnhABu7dzWrcyYkwPbvx5l1gRSPAX/0n+OBtSiVCKtGFv4n+ecWUHU0tCG9LSSwoZZx673zBQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,20 +395,6 @@
|
||||
"SQLitePCLRaw.core": "2.1.12"
|
||||
}
|
||||
}
|
||||
},
|
||||
"net10.0/android-arm64": {
|
||||
"libsodium": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.0.22, )",
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "KPD9SloJFclrsjnhABu7dzWrcyYkwPbvx5l1gRSPAX/0n+OBtSiVCKtGFv4n+ecWUHU0tCG9LSSwoZZx673zBQ=="
|
||||
},
|
||||
"SQLitePCLRaw.lib.e_sqlite3": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.1.12, )",
|
||||
"resolved": "2.1.12",
|
||||
"contentHash": "fWi8Dbknuhgg72fWinIdjXVaqO1hHL4YBBwVLnr7e1c9TAZwJ0QE38j9syW1hwx6HaqEVTwI+O07WPdZn8Rp0w=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,20 +252,6 @@
|
||||
"SQLitePCLRaw.core": "2.1.12"
|
||||
}
|
||||
}
|
||||
},
|
||||
"net10.0/android-arm64": {
|
||||
"libsodium": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.0.22, )",
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "KPD9SloJFclrsjnhABu7dzWrcyYkwPbvx5l1gRSPAX/0n+OBtSiVCKtGFv4n+ecWUHU0tCG9LSSwoZZx673zBQ=="
|
||||
},
|
||||
"SQLitePCLRaw.lib.e_sqlite3": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[2.1.12, )",
|
||||
"resolved": "2.1.12",
|
||||
"contentHash": "fWi8Dbknuhgg72fWinIdjXVaqO1hHL4YBBwVLnr7e1c9TAZwJ0QE38j9syW1hwx6HaqEVTwI+O07WPdZn8Rp0w=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,14 +65,6 @@
|
||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"net10.0/android-arm64": {
|
||||
"libsodium": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.0.22, )",
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "KPD9SloJFclrsjnhABu7dzWrcyYkwPbvx5l1gRSPAX/0n+OBtSiVCKtGFv4n+ecWUHU0tCG9LSSwoZZx673zBQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,14 +65,6 @@
|
||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"net10.0/android-arm64": {
|
||||
"libsodium": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.0.22, )",
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "KPD9SloJFclrsjnhABu7dzWrcyYkwPbvx5l1gRSPAX/0n+OBtSiVCKtGFv4n+ecWUHU0tCG9LSSwoZZx673zBQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,6 @@
|
||||
"resolved": "10.0.10",
|
||||
"contentHash": "f5VCIE7AJpd5YvzNTeMGVzQIgyE9tX+AreTYwQF+REbu+DZo/2Ae+jNSwhPEYrVz6RRkd7y8ubXjk6Nn6Ka+Cg=="
|
||||
}
|
||||
},
|
||||
"net10.0/android-arm64": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,14 +35,6 @@
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "KPD9SloJFclrsjnhABu7dzWrcyYkwPbvx5l1gRSPAX/0n+OBtSiVCKtGFv4n+ecWUHU0tCG9LSSwoZZx673zBQ=="
|
||||
}
|
||||
},
|
||||
"net10.0/android-arm64": {
|
||||
"libsodium": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.0.22, )",
|
||||
"resolved": "1.0.22",
|
||||
"contentHash": "KPD9SloJFclrsjnhABu7dzWrcyYkwPbvx5l1gRSPAX/0n+OBtSiVCKtGFv4n+ecWUHU0tCG9LSSwoZZx673zBQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user