From 4321340a23e0a5a61668bf3c2d115469dcff7da1 Mon Sep 17 00:00:00 2001 From: Hammed Abass Date: Thu, 16 Jul 2026 21:40:13 +0200 Subject: [PATCH 1/4] docs: update privacy disclosures for store release --- docs/app/privacy/page.tsx | 64 +++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/docs/app/privacy/page.tsx b/docs/app/privacy/page.tsx index 182ea39..575983e 100644 --- a/docs/app/privacy/page.tsx +++ b/docs/app/privacy/page.tsx @@ -31,7 +31,7 @@ export default function PrivacyPage() { This policy explains what moves between devices, what stays local, and what is sent only when you choose to share diagnostics or a bug report.

-

Effective July 16, 2026 · Version 1.0

+

Effective July 16, 2026 · Version 1.1

@@ -65,8 +65,10 @@ export default function PrivacyPage() {

This policy covers the official VniDrop website, the VniDrop applications for Android, iOS, macOS, Windows, and Linux, and the diagnostics service configured by - the official project. In this policy, “VniDrop,” “we,” and “us” refer to the - maintainers of the official VniDrop project and the official builds they distribute. + the official project. For an official release, VniDrop’s data controller is the + individual publisher named in the applicable app-store listing. In this policy, + “VniDrop,” “we,” and “us” also include the maintainers acting on that publisher’s + behalf. The publisher can be reached at support@sudosy.fr.

VniDrop is open-source software. A build distributed or operated by someone else @@ -131,12 +133,13 @@ export default function PrivacyPage() {

Optional diagnostics and bug reports

Automatic product diagnostics

- When an official build includes diagnostics, automatic usage events and crash - reports are disabled until you enable “Share diagnostics.” If enabled, VniDrop may - send an anonymous installation ID, app version, platform, sparse event names and - properties, crash type and message, a redacted stack trace, timestamps, and recent - in-app breadcrumbs. You can turn this off at any time; doing so also removes pending - local crash reports. + Official releases indicate in the app settings whether automatic product + diagnostics are included. When included, automatic usage events and crash reports + are disabled until you enable “Share diagnostics.” If enabled, VniDrop may send an + anonymous installation ID, app version, platform, sparse event names and properties, + crash type and message, a redacted stack trace, timestamps, and recent in-app + breadcrumbs. You can turn this off at any time; doing so also removes pending local + crash reports.

User-submitted bug reports

@@ -165,11 +168,10 @@ export default function PrivacyPage() { nearby devices.

- The hosting and security infrastructure may process routine request information—such + Vercel hosts the static site, while Cloudflare proxies requests and provides DNS and + security services for the domain. They may process routine request information—such as IP address, time, requested page, referrer, and browser user agent—to deliver the - site, maintain reliability, and prevent abuse. The live hosting provider must be - identified in this policy before public deployment if it differs from the providers - described below. + site, maintain reliability, and prevent abuse.

@@ -210,11 +212,19 @@ export default function PrivacyPage() { Relays process connection metadata but cannot decrypt transfer contents. +
+
Vercel
+
+ Hosts and serves the static VniDrop website and processes routine request and + delivery metadata. +
+
Cloudflare
- The project’s diagnostics design uses Cloudflare Workers, D1, and R2. - Cloudflare also processes source IPs for request delivery and abuse controls. + Proxies website requests and provides DNS, security, and abuse controls. When + the optional diagnostics service is configured, it uses Cloudflare Workers, D1, + and R2.
@@ -250,6 +260,14 @@ export default function PrivacyPage() { Cloudflare ,{" "} + + Vercel + + ,{" "} Google @@ -366,18 +384,12 @@ export default function PrivacyPage() {

Contact

- VniDrop is currently maintained as an open-source project and does not yet publish a - dedicated privacy email or postal address. For a privacy question or request, open a - request in the project issue tracker. Do not put an invitation, file content, - credentials, or other sensitive information in a public issue. + For a privacy question, rights request, or support request, email + support@sudosy.fr. Do not put an invitation, file content, credentials, or other + sensitive information in a public issue.

- - Contact the maintainers + + Email support@sudosy.fr
From 97dd9b32beadaa5736e42a99329fd0eef76bb979 Mon Sep 17 00:00:00 2001 From: Hammed Abass Date: Thu, 16 Jul 2026 22:34:02 +0200 Subject: [PATCH 2/4] ci: build Windows Store release artifacts --- .github/workflows/windows-store.yml | 157 ++++++++++ desktopApp/build.gradle.kts | 25 +- gradle.properties | 5 + packaging/windows/AppxManifest.xml | 56 ++++ .../windows/Assets/Square150x150Logo.png | Bin 0 -> 11208 bytes packaging/windows/Assets/Square44x44Logo.png | Bin 0 -> 2296 bytes ...x44Logo.targetsize-16_altform-unplated.png | Bin 0 -> 1110 bytes ...x44Logo.targetsize-24_altform-unplated.png | Bin 0 -> 1429 bytes ...44Logo.targetsize-256_altform-unplated.png | Bin 0 -> 24409 bytes ...x44Logo.targetsize-32_altform-unplated.png | Bin 0 -> 1856 bytes ...x44Logo.targetsize-44_altform-unplated.png | Bin 0 -> 2553 bytes ...x44Logo.targetsize-48_altform-unplated.png | Bin 0 -> 2734 bytes packaging/windows/Assets/StoreLogo.png | Bin 0 -> 2606 bytes packaging/windows/README.md | 105 +++++++ packaging/windows/build-msix.ps1 | 280 ++++++++++++++++++ shared/build.gradle.kts | 20 ++ 16 files changed, 645 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/windows-store.yml create mode 100644 packaging/windows/AppxManifest.xml create mode 100644 packaging/windows/Assets/Square150x150Logo.png create mode 100644 packaging/windows/Assets/Square44x44Logo.png create mode 100644 packaging/windows/Assets/Square44x44Logo.targetsize-16_altform-unplated.png create mode 100644 packaging/windows/Assets/Square44x44Logo.targetsize-24_altform-unplated.png create mode 100644 packaging/windows/Assets/Square44x44Logo.targetsize-256_altform-unplated.png create mode 100644 packaging/windows/Assets/Square44x44Logo.targetsize-32_altform-unplated.png create mode 100644 packaging/windows/Assets/Square44x44Logo.targetsize-44_altform-unplated.png create mode 100644 packaging/windows/Assets/Square44x44Logo.targetsize-48_altform-unplated.png create mode 100644 packaging/windows/Assets/StoreLogo.png create mode 100644 packaging/windows/README.md create mode 100644 packaging/windows/build-msix.ps1 diff --git a/.github/workflows/windows-store.yml b/.github/workflows/windows-store.yml new file mode 100644 index 0000000..357f313 --- /dev/null +++ b/.github/workflows/windows-store.yml @@ -0,0 +1,157 @@ +name: Windows Store package + +on: + pull_request: + paths: + - ".github/workflows/windows-store.yml" + - "packaging/windows/**" + - "assets/windows/**" + - "desktopApp/**" + - "shared/**" + - "crates/vnidrop/**" + - "Cargo.toml" + - "Cargo.lock" + - "build.gradle.kts" + - "settings.gradle.kts" + - "gradle.properties" + - "gradle/**" + - "gradlew" + - "gradlew.bat" + push: + tags: + - "v*.*.*" + workflow_dispatch: + inputs: + version: + description: Release version in MAJOR.MINOR.PATCH form + required: true + default: "1.0.0" + type: string + +permissions: + contents: read + +concurrency: + group: windows-store-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + build-msix: + name: Build unsigned Store MSIX (x64) + runs-on: windows-2025 + timeout-minutes: 90 + env: + CARGO_TERM_COLOR: always + + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Set up JDK 21 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + with: + distribution: temurin + java-version: "21.0.11+10" + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 + + - name: Set up Rust 1.91 + shell: pwsh + run: | + rustup toolchain install 1.91.0-x86_64-pc-windows-msvc --profile minimal + rustup default 1.91.0-x86_64-pc-windows-msvc + rustc --version --verbose + cargo --version + + - name: Cache Cargo + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: windows-x64-cargo-1.91.0-${{ hashFiles('Cargo.lock') }} + restore-keys: | + windows-x64-cargo-1.91.0- + + - name: Resolve Store version + id: version + shell: pwsh + env: + REQUESTED_VERSION: ${{ inputs.version || '1.0.0' }} + run: | + $version = $env:REQUESTED_VERSION + if ($env:GITHUB_REF_TYPE -eq "tag") { + if ($env:GITHUB_REF_NAME -notmatch "^v[0-9]+\.[0-9]+\.[0-9]+$") { + throw "Store release tags must use vMAJOR.MINOR.PATCH" + } + $version = $env:GITHUB_REF_NAME.Substring(1) + } + + if ($version -notmatch "^[0-9]+\.[0-9]+\.[0-9]+$") { + throw "Version must use MAJOR.MINOR.PATCH" + } + $parts = $version.Split(".") + for ($index = 0; $index -lt $parts.Count; $index++) { + $part = $parts[$index] + $number = 0 + if (-not [int]::TryParse($part, [ref] $number) -or $number.ToString() -ne $part) { + throw "Version components must be canonical integers" + } + if ($number -lt $(if ($index -eq 0) { 1 } else { 0 }) -or $number -gt 65535) { + throw "Version components must be between 0 and 65535, with a non-zero major" + } + } + + "app=$version" >> $env:GITHUB_OUTPUT + "package=$version.0" >> $env:GITHUB_OUTPUT + + - name: Test and build release app image + shell: pwsh + run: | + $arguments = @( + ":shared:jvmTest" + ":desktopApp:createReleaseDistributable" + "-Pvnidrop.version=${{ steps.version.outputs.app }}" + "-Pvnidrop.desktop.rustVariant=release" + "-Pvnidrop.diagnostics.included=false" + "--no-daemon" + "--no-configuration-cache" + "--stacktrace" + ) + & .\gradlew.bat @arguments + if ($LASTEXITCODE -ne 0) { + throw "Gradle release build failed with exit code $LASTEXITCODE" + } + + - name: Create and validate Store package + shell: pwsh + run: | + $arguments = @( + "-Version", "${{ steps.version.outputs.app }}" + "-AppImage", ".\desktopApp\build\compose\binaries\main-release\app\VniDrop" + "-OutputDirectory", ".\build\release\windows" + ) + & .\packaging\windows\build-msix.ps1 @arguments + + - name: Upload Store artifacts + if: github.event_name != 'pull_request' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: vnidrop-${{ steps.version.outputs.app }}-windows-store-x64 + path: build/release/windows/ + if-no-files-found: error + retention-days: 90 + compression-level: 0 + + - name: Summarize package + shell: pwsh + run: | + "### Windows Store package" >> $env:GITHUB_STEP_SUMMARY + "- App version: ${{ steps.version.outputs.app }}" >> $env:GITHUB_STEP_SUMMARY + "- MSIX version: ${{ steps.version.outputs.package }}" >> $env:GITHUB_STEP_SUMMARY + "- Architecture: x64" >> $env:GITHUB_STEP_SUMMARY + "- Signing: unsigned Store submission; Microsoft signs after certification" >> $env:GITHUB_STEP_SUMMARY diff --git a/desktopApp/build.gradle.kts b/desktopApp/build.gradle.kts index deeb310..d1b896a 100644 --- a/desktopApp/build.gradle.kts +++ b/desktopApp/build.gradle.kts @@ -6,6 +6,20 @@ plugins { alias(libs.plugins.composeCompiler) } +val appVersion = providers.gradleProperty("vnidrop.version").get() +val appVersionParts = appVersion.split(".") +require( + appVersionParts.size == 3 && + appVersionParts.mapIndexed { index, part -> + val number = part.toIntOrNull() + number != null && + number.toString() == part && + number in (if (index == 0) 1 else 0)..65535 + }.all { it }, +) { + "vnidrop.version must be MAJOR.MINOR.PATCH with numeric components from 0 to 65535 and a non-zero major" +} + dependencies { implementation(projects.shared) @@ -20,18 +34,23 @@ dependencies { compose.desktop { application { mainClass = "com.vnidrop.app.MainKt" + buildTypes.release.proguard.isEnabled.set(false) nativeDistributions { - targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) - packageName = "com.vnidrop.app" - packageVersion = "1.0.0" + targetFormats(TargetFormat.Dmg, TargetFormat.Deb) + packageName = "VniDrop" + packageVersion = appVersion + description = "Send files directly across your devices" + vendor = "Sudosy Labs" macOS { + bundleID = "com.vnidrop.app" iconFile.set(project.file("../assets/macos/app-icon.icns")) } windows { iconFile.set(project.file("../assets/windows/app-icon.ico")) } linux { + packageName = "vnidrop" iconFile.set(project.file("../assets/linux/app-icon.png")) } fileAssociation( diff --git a/gradle.properties b/gradle.properties index 34d6c2f..35d3b69 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,6 +6,11 @@ kotlin.mpp.enableCInteropCommonization=true org.gradle.jvmargs=-Xmx4096M -Dfile.encoding=UTF-8 org.gradle.configuration-cache=true org.gradle.caching=true + +# Product version used by desktop packaging. Release workflows override this +# from the vMAJOR.MINOR.PATCH tag. +vnidrop.version=1.0.0 + #Android android.builtInKotlin=false android.newDsl=false diff --git a/packaging/windows/AppxManifest.xml b/packaging/windows/AppxManifest.xml new file mode 100644 index 0000000..5c00254 --- /dev/null +++ b/packaging/windows/AppxManifest.xml @@ -0,0 +1,56 @@ + + + + + Vnidrop + Sudosy Labs + Send files directly across your devices. + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + VniDrop Invitation + Assets\Square44x44Logo.png + + .vnd + + + + + + + diff --git a/packaging/windows/Assets/Square150x150Logo.png b/packaging/windows/Assets/Square150x150Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1a4478aaf48a5aac7eb5e6df5ca1fe3c54783ad5 GIT binary patch literal 11208 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 WC@k&}YvcH@i&jQLQM^(V81O$vCcbn4 literal 0 HcmV?d00001 diff --git a/packaging/windows/Assets/Square44x44Logo.png b/packaging/windows/Assets/Square44x44Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f610f224508aa2751e4b8c8c0a93611b7539285a GIT binary patch literal 2296 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91ET97b1ONa40RR91EC2ui0Q_#}qW}O1Vo5|nR9FesnQLquR~5(4Joafj z8^^?XI)W%EA_)+;R)rF%)Cwd@KvkPowEcnvA0im>K7#V%u7W=;zJ>*O*XyizcOIAjIWu=W_KtVfDI(3a#`n&hbI<+VbI*M) z(H$0yPIyO0N3*5UKu^71vpSJqu1r2(^eUB0)$QB2H`B^43H!*G?arhH$WsMqQTo_+qz!F~INoQ^e>%i}|}+4`FRye)z2 zE|;f=IszUauk2|yoEx`=G*&4yOo62>G+K2x1gB%=ZflZRm?;h&`7jTx&u`j%q}ZL` z6&KLy%0-{5SKx1^k}UqeV!cT#Hbg44Xli_OTv4uQkmnL9j0t|S-9%QdwJ6-+M8gjUwy=THUh2#l$n$?6aGtBkK*PD*>6Zcho(r9dTv)j_N#xAU%j=YF zn}f{A@8S}rQmF@X;VLblRt8@Ub0_*))4y(dA>Fz-qZ=#k$84vk!lG zxJh5QH%lwmS&>gK)@K;zs*+jiLH?vzxL&s{Ls5$(HgBSKRzN87f|+l-cSTTlk_uw@5}_vt2~_k|FLecSF(1XB@FG zv6VvDWiiLgFdM%^m+vXMaIy&tqt}fVyDdO#3tU)b(6@e_qjPU~bnf2KDaurd#aI)Vly6`IdW1!hqdPBo!1Ld)`pTi_K?E{p!*MI(F@QB_T7ert*)6~_!aSHx2NsXulR2Z@ps%CX)&vi>sgGfbc(_GaZe?WAn02M` z_`u)NLMkw?g=W|fV%<0_rX5JiHpmf+@fMTAsr?Q$ zuvy|&m7Brxyxj7ZiY@&9YfiBF=kFmTuXurVLs-1)`dDXDNCjqJY+2e-BXrB=d*y&h zGi9GHANOQq&omm=!={Fz`7|-|a#P9_dkxtaYv{;5AZKA4Vdo&+CZqy)tv19mQUNPs zpim)Ocf+7X*G7G6)`CoF2>xkU-idL8C(rv-uPExji}$^uMPXtM&YOE~Oupw+0{5&n zsrWfqg}XNf%U#KXsGhusnPm;xu9xnU zNBgl62%)hWl4G8~S8XzB^RE99aQ~Mq8u*$eQ^2k)J)TYVU$$X-lOV)X&Cn0BbY-MY4FE7G zS7=y@CeC7>{bPgf`)Q5}7&NC|Y|`Wf3_?H@yG+^!%kKVRP6pI-KdZ^q$JYfK*qKwb z2|aZ8UJQs1LPx-?XXQqdcKAMYdxa6a#Pm@6?n+K0{e*>VZ;pWg!- z(qd^8;qB)K|8nWvJ1%X6Mb~^0{@NYP9%H9nx_H8sX-}4Hz;Z)*#^AyF$Zv~s1Jtf& zX3IOS@Ck6GQmOX!^-rNtf4hSGZQFMY-ZhfwkK#`rcCoT8B6-DCJL8{0g)~pBAoG=lL^eW-W! z3b_mvm*4`|CNI5O=-T{NyBo|T#r^PCes*I{p1$nU4LmoeeA&3$xIXRbGpQGIZ0`m$ zbrnm}&)2Qx>z7_j`bKxcg?0=0XXz&cW@!OT$`~(C-!oThz5yS+Eg|?(W<2pnnP|{0 z20wB{**kaE_T+N*WB-qzy|8JXbUk;tR%;x1zRk~GO9ICm@LBp{G0t^Ir2h-Z+{1ys S%3}op0000!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBC{d9b;hE;^%b*2hb1<+l zN-=;;U<6`2Mrk)1Mw+X6zEku zE}%|Wu-S33{Es;S4CKe2E{-7*s_9A=(X~99OlFFjIU;h8!o6~v7TCE=XkdIgH@>C(eNnZw@jIdKJKF0T z&TX_l{3osc^X=KJKd!fhGM*N96;8SApfx+ge4fnw<4OG!>PBu zLY=2hu=-f2_C>om{8y|fj8gJws5jZBEo+jrlxcqI#A*6B;^x@ym=G6x-!{hM+s}7- z6C1(1yaE#I~8w zy`#Ns!_3+BdTYKLpY+cDlx=?P+rICm2mdK?9GGi7yIs`XJ@??*rWMooN>$75elGao c|MCB9s|vq=Y)f460F-k)UHx3vIVCg!02NJwW&i*H literal 0 HcmV?d00001 diff --git a/packaging/windows/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/packaging/windows/Assets/Square44x44Logo.targetsize-24_altform-unplated.png new file mode 100644 index 0000000000000000000000000000000000000000..5707cd788977db166e6a5215d272600dd72e65ae GIT binary patch literal 1429 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 literal 0 HcmV?d00001 diff --git a/packaging/windows/Assets/Square44x44Logo.targetsize-32_altform-unplated.png b/packaging/windows/Assets/Square44x44Logo.targetsize-32_altform-unplated.png new file mode 100644 index 0000000000000000000000000000000000000000..677abb4bb15ac4ee1dab5e3bafce05b18604feba GIT binary patch literal 1856 zcmZ8i3pkW%8-B-OmT}&4?l6tb>Bq>a492vC!7wpqXM~KipD|-*n2Bf{5+$uDQp;4R zkS&8Q)t^Hs7VTJDQZi^qYta=cN&MfG>|Xm`*YiEkcfa?2KkxHh?{$57L?3q*gdPF_ zpn~^s^@B1}8VYde$xcam3njVey@b60+&rbULX($nhI{xC07x+efS(P(G6eBo0gz+~ zz;q}8m{I_=nHO&FcZ4>0kraFsfdEXQS^>zx^nla>1_c(TzfrrvjDhTDTn2z+u|RH} z;{#>s@_<6B`I2P?uyr#?RGlT@JlDp<*~3CI*e>a=8{0el{#ZZY}5`baDFeu6s!o#aZ%!m@Sc;v1`t$zIS>~!!MFAlPihx6=u1x zDrDe<=C_qqxw#6<;w){V^2s!j_CeQ?V~v-Z{H~IeuuH_dp*Zj30b%*t`NYh^YC;`8 znH#lse(VGHo5!=>eii*~ea>u2(7lD97AkZvot#`7;8RZUi(J@U$kyvu$hG^i#`dp5 zwyY9Mo8p&72WR}aRY4}f7++GY|FAQ1)l*m)i>B1mUvGON&^3waK3%@wZsp|?_J@#P zBoEVS?>rcrSxrwE8L&a^Hqf{EwBRo3vN>-HQ_l;t6O`j5DRtIo^7}@87nkX=1C(tq zV_r{hpU)8*aUS)`i!M($YEHGY-Gh#t4mQN|CfcXTy*+9`yj*s?`?}B}H=-iBOfC=E zV|bS8J}6&sRf{_=kGtt)%)#FBh@~@~o-nj3z87 zQ#k)a<{3k0waq@g-Pc(wq%|a=_&F*^4xH@ZX8%ae7G-ZrzCjz#GH6l-1#`?qt=%~P z;0Bx2=5eib#&>~+GQ5?^`H2_)T}Ib!g)PWdmp#SF1SPAn?HID3Ss1;v#Jr99p)p32Cahu z{vDxC3h)UpQ5dR4rWgTKj3=Al6fplZ>*(20lKOu9muJt~Evbhu$@Kd*mU?&@X!3C) zdqHcb21Y%*X8Ew&W@r6WPU3;Oj;Czqlj#gYf$DvVZk#FKZfiwL^hLtbs>>ow`Krc+ zPZ_3LWc1Uq$a`upJA27-@m0LVW_orA5H~eG!;CFLLS;dK$87g&ecL)kn z+kR7%e~kaLodf6J8#z9PK>v8|8vMKY?%`mt7s414g^U&$sSj*jfy69*#T z$}v`zV_t}X1`=3(^g#Y+YVEiljM$g|kg?0tIkIVZyUC&~nPqq%Xx-Fzv!f6A9QaRp z!1L`21-dYzNOv^ggN+KPemC+!)P6?xsUXgVWc#{UC|mlZX}>$Zr1vVWS*w19I&B&h zen!8jxaEHtqZ-7FM$v-LNNUJAv$Zm<$Y2n&b64|~W%#N|NP~yhMR8~*YU{w{iQS5# zF+qyMQ1XtcIy;qKVxFF1nTxe*YfAmc^NnJ&gW9o^Z$7ZK z;AvY@w-6Uoz1>0FXeBvX$ViO}|Jb-#1G|xRi;I3gaVlQtNYp8vXvV%iL{vIIN9oNI z8#T*=lLpBvfAsWMT#=tCUNZu--N)uwnmbEw85;?yB~SSg3JD- aydqoG^(&=vcBWeTkHGKqajpM8H1q%cPVMUe literal 0 HcmV?d00001 diff --git a/packaging/windows/Assets/Square44x44Logo.targetsize-44_altform-unplated.png b/packaging/windows/Assets/Square44x44Logo.targetsize-44_altform-unplated.png new file mode 100644 index 0000000000000000000000000000000000000000..14a95786fcbf09377a69c302ed5df126462c0182 GIT binary patch literal 2553 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 QsQ>@~07*qoM6N<$g1>dy&Hw-a literal 0 HcmV?d00001 diff --git a/packaging/windows/README.md b/packaging/windows/README.md new file mode 100644 index 0000000..a7e87b0 --- /dev/null +++ b/packaging/windows/README.md @@ -0,0 +1,105 @@ +# Windows Microsoft Store packaging + +This directory turns the Compose Desktop Windows app image into the unsigned +MSIX artifacts accepted by Partner Center. Microsoft signs the package after +certification, so this build does not use a PFX, certificate, HSM, or signing +secret. + +## Product identity + +These values came from the Partner Center Product identity page and are +case-sensitive: + +| Field | Value | +| --- | --- | +| Package identity name | SudosyLabs.Vnidrop | +| Publisher | CN=6456DC8E-2C31-44BD-AACC-2E6813C833CB | +| Publisher display name | Sudosy Labs | +| Reserved Store name | Vnidrop | +| Application ID | VniDrop | +| Store ID | 9NJ5Q0FG7TGL | + +The package identity name, publisher, and Application ID must remain stable +after the first release. The manifest display name uses the exact reserved Store +name; the product's in-app branding and launcher remain `VniDrop`. + +The initial package targets Windows Desktop x64, Windows 10 version 2004 +(build 19041) or later. The fourth MSIX version component is reserved by the +Store, so app version 1.2.3 becomes package version 1.2.3.0. + +## GitHub Actions + +The Windows Store package workflow runs automatically for relevant pull +requests, for release tags matching vMAJOR.MINOR.PATCH, and by manual dispatch. +Pull requests build and validate without retaining an artifact. Tags and manual +runs retain: + +- VniDrop_VERSION_x64.msix +- VniDrop_VERSION_x64.msixupload +- build metadata +- SHA-256 checksums + +The preferred Partner Center upload is the msixupload file. It is an upload +envelope containing the x64 MSIX. The MSIX is intentionally unsigned and is not +a public sideloading artifact. Do not attach it to a public GitHub Release +unless an independent production-signing path is added. + +The workflow explicitly selects Gobley's release Rust variant and rejects a +package containing the debug native JAR. It also verifies the bundled JVM, +vnidrop.dll, app version, manifest identity, architecture, and launcher after +MakeAppx unpacks the finished package. + +## First Store release + +Microsoft's current GitHub Actions publishing flow is for updates to an +already-live free product. For the first release: + +1. Run this workflow from a release tag or by manual dispatch. +2. Download the retained artifact. +3. Test that exact build on an interactive Windows VM. Local installation needs + an ephemeral development signature trusted only by that VM; this is not a + production signing key. +4. Upload the msixupload file to the current Partner Center draft. +5. Confirm that Partner Center parses the expected identity, version, x64 + architecture, Windows.Desktop target, en-US language, and runFullTrust + capability. +6. Complete listing, screenshots, certification notes, and submit. + +Use this restricted-capability justification in Submission options: + +> VniDrop is a classic JVM desktop application that loads its bundled native +> Rust and JVM libraries and needs normal user-level filesystem and network +> access to transfer user-selected files directly between devices. + +After the first release is certified and live, Store publication can be added +as a separate protected job. Keep its Partner Center credentials in a GitHub +Environment, not in this build job: + +- AZURE_AD_TENANT_ID +- AZURE_AD_APPLICATION_CLIENT_ID +- AZURE_AD_APPLICATION_SECRET +- SELLER_ID + +The Store ID is a non-secret variable. + +## Manual build on Windows + +From the repository root: + +~~~powershell +.\gradlew.bat :shared:jvmTest :desktopApp:createReleaseDistributable -Pvnidrop.version=1.0.0 -Pvnidrop.desktop.rustVariant=release -Pvnidrop.diagnostics.included=false --no-daemon --no-configuration-cache --stacktrace + +.\packaging\windows\build-msix.ps1 -Version 1.0.0 -AppImage .\desktopApp\build\compose\binaries\main-release\app\VniDrop -OutputDirectory .\build\release\windows +~~~ + +The packaging script requires Windows SDK 10.0.26100.0. It uses MakePri to +index the scale-qualified visual assets, then MakeAppx with SHA-256 block maps +and manifest validation enabled. + +Microsoft references: + +- [MSIX Store package requirements](https://learn.microsoft.com/en-us/windows/apps/publish/publish-your-app/msix/app-package-requirements) +- [Manual desktop MSIX packaging](https://learn.microsoft.com/en-us/windows/msix/desktop/desktop-to-uwp-manual-conversion) +- [MakeAppx](https://learn.microsoft.com/en-us/windows/msix/package/create-app-package-with-makeappx-tool) +- [Uploading MSIX packages](https://learn.microsoft.com/en-us/windows/apps/publish/publish-your-app/msix/upload-app-packages) +- [GitHub Actions Store updates](https://learn.microsoft.com/en-us/windows/apps/publish/msstore-dev-cli/github-actions) diff --git a/packaging/windows/build-msix.ps1 b/packaging/windows/build-msix.ps1 new file mode 100644 index 0000000..dfe7027 --- /dev/null +++ b/packaging/windows/build-msix.ps1 @@ -0,0 +1,280 @@ +[CmdletBinding()] +param( + [Parameter(Mandatory)] + [string] $Version, + + [Parameter(Mandatory)] + [string] $AppImage, + + [Parameter(Mandatory)] + [string] $OutputDirectory, + + [string] $WindowsSdkVersion = "10.0.26100.0" +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" + +function Assert-Condition { + param( + [bool] $Condition, + [string] $Message + ) + + if (-not $Condition) { + throw $Message + } +} + +function Invoke-Checked { + param( + [string] $FilePath, + [string[]] $Arguments + ) + + & $FilePath @Arguments + if ($LASTEXITCODE -ne 0) { + throw "$FilePath failed with exit code $LASTEXITCODE" + } +} + +function Read-ZipEntry { + param( + [string] $ArchivePath, + [string] $EntryPath + ) + + $archive = [System.IO.Compression.ZipFile]::OpenRead($ArchivePath) + try { + $entry = $archive.GetEntry($EntryPath) + if ($null -eq $entry) { + throw "$ArchivePath does not contain $EntryPath" + } + $reader = [System.IO.StreamReader]::new($entry.Open()) + try { + return $reader.ReadToEnd() + } + finally { + $reader.Dispose() + } + } + finally { + $archive.Dispose() + } +} + +function Get-ZipEntryLength { + param( + [string] $ArchivePath, + [string] $EntryPath + ) + + $archive = [System.IO.Compression.ZipFile]::OpenRead($ArchivePath) + try { + $entry = $archive.GetEntry($EntryPath) + if ($null -eq $entry) { + throw "$ArchivePath does not contain $EntryPath" + } + return $entry.Length + } + finally { + $archive.Dispose() + } +} + +if ([System.Environment]::OSVersion.Platform -ne [System.PlatformID]::Win32NT) { + throw "MSIX packaging must run on Windows" +} + +$versionParts = $Version.Split(".") +Assert-Condition ($versionParts.Count -eq 3) "Version must use MAJOR.MINOR.PATCH" +for ($index = 0; $index -lt $versionParts.Count; $index++) { + $part = $versionParts[$index] + $number = 0 + Assert-Condition ([int]::TryParse($part, [ref] $number)) "Version components must be integers" + Assert-Condition ($number.ToString() -eq $part) "Version components must not contain leading zeroes" + Assert-Condition ($number -ge $(if ($index -eq 0) { 1 } else { 0 }) -and $number -le 65535) "Version components must be between 0 and 65535, with a non-zero major" +} +$packageVersion = "$Version.0" + +$appImagePath = (Resolve-Path -LiteralPath $AppImage).Path +Assert-Condition (Test-Path -LiteralPath $appImagePath -PathType Container) "App image not found: $AppImage" +Assert-Condition (Test-Path -LiteralPath (Join-Path $appImagePath "VniDrop.exe") -PathType Leaf) "The app image does not contain VniDrop.exe" +Assert-Condition (Test-Path -LiteralPath (Join-Path $appImagePath "runtime\bin\server\jvm.dll") -PathType Leaf) "The app image does not contain its bundled JVM" + +Add-Type -AssemblyName System.IO.Compression.FileSystem +$appFiles = @(Get-ChildItem -LiteralPath $appImagePath -Recurse -File) +$debugRustJars = @($appFiles | Where-Object { $_.Name -match "^shared-win32-x86-64-debug-.+\.jar$" }) +Assert-Condition ($debugRustJars.Count -eq 0) "The app image contains a debug Rust runtime JAR" +$releaseRustJars = @($appFiles | Where-Object { $_.Name -match "^shared-win32-x86-64-(?!debug-).+\.jar$" }) +Assert-Condition ($releaseRustJars.Count -eq 1) "Expected exactly one release Rust runtime JAR" +$nativeDllLength = Get-ZipEntryLength -ArchivePath $releaseRustJars[0].FullName -EntryPath "win32-x86-64/vnidrop.dll" +Assert-Condition ($nativeDllLength -gt 0) "The release Rust runtime JAR contains an empty vnidrop.dll" + +$sharedJars = @($appFiles | Where-Object { $_.Name -match "^shared-jvm-.+\.jar$" }) +Assert-Condition ($sharedJars.Count -eq 1) "Expected exactly one shared JVM JAR" +$sharedManifest = Read-ZipEntry -ArchivePath $sharedJars[0].FullName -EntryPath "META-INF/MANIFEST.MF" +Assert-Condition ($sharedManifest -match "(?m)^Implementation-Version: $([regex]::Escape($Version))\r?$") "The packaged app version does not match $Version" + +$programFilesX86 = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::ProgramFilesX86) +$makeAppxPath = Join-Path $programFilesX86 "Windows Kits\10\bin\$WindowsSdkVersion\x64\MakeAppx.exe" +$makePriPath = Join-Path $programFilesX86 "Windows Kits\10\bin\$WindowsSdkVersion\x64\MakePri.exe" +Assert-Condition (Test-Path -LiteralPath $makeAppxPath -PathType Leaf) "MakeAppx.exe from Windows SDK $WindowsSdkVersion was not found" +Assert-Condition (Test-Path -LiteralPath $makePriPath -PathType Leaf) "MakePri.exe from Windows SDK $WindowsSdkVersion was not found" + +$outputPath = [System.IO.Path]::GetFullPath($OutputDirectory) +[System.IO.Directory]::CreateDirectory($outputPath) | Out-Null +$artifactBaseName = "VniDrop_" + $Version + "_x64" +$msixPath = Join-Path $outputPath "$artifactBaseName.msix" +$uploadPath = Join-Path $outputPath "$artifactBaseName.msixupload" +$buildInfoPath = Join-Path $outputPath "$artifactBaseName.build-info.json" +$checksumsPath = Join-Path $outputPath "SHA256SUMS" +@($msixPath, $uploadPath, $buildInfoPath, $checksumsPath) | + Where-Object { Test-Path -LiteralPath $_ } | + ForEach-Object { Remove-Item -LiteralPath $_ -Force } + +$stageRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("vnidrop-msix-" + [System.Guid]::NewGuid().ToString("N")) +$packageRoot = Join-Path $stageRoot "package" +$unpackedRoot = Join-Path $stageRoot "unpacked" +$priConfigPath = Join-Path $stageRoot "priconfig.xml" +[System.IO.Directory]::CreateDirectory($packageRoot) | Out-Null + +try { + Get-ChildItem -LiteralPath $appImagePath -Force | Copy-Item -Destination $packageRoot -Recurse -Force + Copy-Item -LiteralPath (Join-Path $PSScriptRoot "Assets") -Destination $packageRoot -Recurse -Force + + $manifestTemplate = Get-Content -LiteralPath (Join-Path $PSScriptRoot "AppxManifest.xml") -Raw + Assert-Condition (([regex]::Matches($manifestTemplate, "__VERSION__")).Count -eq 1) "AppxManifest.xml must contain exactly one __VERSION__ placeholder" + $manifestText = $manifestTemplate.Replace("__VERSION__", $packageVersion) + [System.IO.File]::WriteAllText( + (Join-Path $packageRoot "AppxManifest.xml"), + $manifestText, + [System.Text.UTF8Encoding]::new($false) + ) + + Invoke-Checked -FilePath $makePriPath -Arguments @( + "createconfig", + "/cf", $priConfigPath, + "/dq", "en-US", + "/o" + ) + Invoke-Checked -FilePath $makePriPath -Arguments @( + "new", + "/pr", $packageRoot, + "/cf", $priConfigPath, + "/mn", (Join-Path $packageRoot "AppxManifest.xml"), + "/of", (Join-Path $packageRoot "resources.pri"), + "/o" + ) + Assert-Condition ((Get-Item -LiteralPath (Join-Path $packageRoot "resources.pri")).Length -gt 0) "MakePri created an empty resources.pri" + + Invoke-Checked -FilePath $makeAppxPath -Arguments @( + "pack", + "/v", + "/h", "SHA256", + "/d", $packageRoot, + "/p", $msixPath, + "/o" + ) + Invoke-Checked -FilePath $makeAppxPath -Arguments @( + "unpack", + "/v", + "/p", $msixPath, + "/d", $unpackedRoot, + "/o" + ) + + [xml] $manifest = Get-Content -LiteralPath (Join-Path $unpackedRoot "AppxManifest.xml") -Raw + $namespaces = [System.Xml.XmlNamespaceManager]::new($manifest.NameTable) + $namespaces.AddNamespace("f", "http://schemas.microsoft.com/appx/manifest/foundation/windows10") + $namespaces.AddNamespace("uap", "http://schemas.microsoft.com/appx/manifest/uap/windows10") + $namespaces.AddNamespace("uap10", "http://schemas.microsoft.com/appx/manifest/uap/windows10/10") + $namespaces.AddNamespace("rescap", "http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities") + $identity = $manifest.SelectSingleNode("/f:Package/f:Identity", $namespaces) + Assert-Condition ($null -ne $identity) "The packed manifest has no Identity" + Assert-Condition ($identity.GetAttribute("Name") -eq "SudosyLabs.Vnidrop") "The packed package identity name is incorrect" + Assert-Condition ($identity.GetAttribute("Publisher") -eq "CN=6456DC8E-2C31-44BD-AACC-2E6813C833CB") "The packed publisher identity is incorrect" + Assert-Condition ($identity.GetAttribute("Version") -eq $packageVersion) "The packed package version is incorrect" + Assert-Condition ($identity.GetAttribute("ProcessorArchitecture") -eq "x64") "The packed package architecture is not x64" + Assert-Condition ($manifest.SelectSingleNode("/f:Package/f:Properties/f:DisplayName", $namespaces).InnerText -eq "Vnidrop") "The packed display name does not match the reserved Store name" + Assert-Condition ($manifest.SelectSingleNode("/f:Package/f:Properties/f:PublisherDisplayName", $namespaces).InnerText -eq "Sudosy Labs") "The packed publisher display name is incorrect" + $targetFamily = $manifest.SelectSingleNode("/f:Package/f:Dependencies/f:TargetDeviceFamily", $namespaces) + Assert-Condition ($null -ne $targetFamily) "The packed manifest has no target device family" + Assert-Condition ($targetFamily.GetAttribute("Name") -eq "Windows.Desktop") "The packed package does not target Windows.Desktop" + Assert-Condition ($null -ne $manifest.SelectSingleNode("/f:Package/f:Capabilities/rescap:Capability[@Name='runFullTrust']", $namespaces)) "The packed package does not declare runFullTrust" + + $application = $manifest.SelectSingleNode("/f:Package/f:Applications/f:Application", $namespaces) + Assert-Condition ($null -ne $application) "The packed manifest has no Application" + Assert-Condition ($application.GetAttribute("Id") -eq "VniDrop") "The packed application ID is incorrect" + $executable = $application.GetAttribute("Executable") + Assert-Condition ($executable -eq "VniDrop.exe") "The packed manifest executable is incorrect" + Assert-Condition ($application.GetAttribute("RuntimeBehavior", "http://schemas.microsoft.com/appx/manifest/uap/windows10/10") -eq "packagedClassicApp") "The packed runtime behavior is incorrect" + Assert-Condition ($application.GetAttribute("TrustLevel", "http://schemas.microsoft.com/appx/manifest/uap/windows10/10") -eq "mediumIL") "The packed trust level is incorrect" + Assert-Condition ($manifest.SelectSingleNode("/f:Package/f:Applications/f:Application/f:Extensions/uap:Extension/uap:FileTypeAssociation/uap:SupportedFileTypes/uap:FileType[text()='.vnd']", $namespaces) -ne $null) "The packed package is missing the .vnd file association" + Assert-Condition (Test-Path -LiteralPath (Join-Path $unpackedRoot $executable) -PathType Leaf) "The packed executable is missing" + Assert-Condition (Test-Path -LiteralPath (Join-Path $unpackedRoot "resources.pri") -PathType Leaf) "The packed resource index is missing" +} +finally { + if (Test-Path -LiteralPath $stageRoot) { + Remove-Item -LiteralPath $stageRoot -Recurse -Force + } +} + +$temporaryZip = Join-Path $outputPath "$artifactBaseName.zip" +if (Test-Path -LiteralPath $temporaryZip) { + Remove-Item -LiteralPath $temporaryZip -Force +} +Compress-Archive -LiteralPath $msixPath -DestinationPath $temporaryZip -CompressionLevel Optimal +Move-Item -LiteralPath $temporaryZip -Destination $uploadPath + +$repoRoot = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "..\..")).Path +$wrapperProperties = Get-Content -LiteralPath (Join-Path $repoRoot "gradle\wrapper\gradle-wrapper.properties") +$gradleDistribution = $wrapperProperties | Where-Object { $_.StartsWith("distributionUrl=") } | Select-Object -First 1 +$sourceCommit = [System.Environment]::GetEnvironmentVariable("GITHUB_SHA") +if ([string]::IsNullOrWhiteSpace($sourceCommit)) { + $sourceCommit = "local" +} +$sourceRef = [System.Environment]::GetEnvironmentVariable("GITHUB_REF") +if ([string]::IsNullOrWhiteSpace($sourceRef)) { + $sourceRef = "local" +} + +$buildInfo = [ordered] @{ + appVersion = $Version + packageVersion = $packageVersion + architecture = "x64" + identityName = "SudosyLabs.Vnidrop" + publisher = "CN=6456DC8E-2C31-44BD-AACC-2E6813C833CB" + storeId = "9NJ5Q0FG7TGL" + sourceCommit = $sourceCommit + sourceRef = $sourceRef + runnerImage = [System.Environment]::GetEnvironmentVariable("ImageOS") + runnerImageVersion = [System.Environment]::GetEnvironmentVariable("ImageVersion") + javaVersion = ((& java --version | Select-Object -First 1) | Out-String).Trim() + rustVersion = ((& rustc --version) | Out-String).Trim() + cargoVersion = ((& cargo --version) | Out-String).Trim() + gradleDistribution = $gradleDistribution + windowsSdkVersion = $WindowsSdkVersion + makeAppxVersion = (Get-Item -LiteralPath $makeAppxPath).VersionInfo.FileVersion + makePriVersion = (Get-Item -LiteralPath $makePriPath).VersionInfo.FileVersion + unsignedForMicrosoftStore = $true + builtAtUtc = [System.DateTimeOffset]::UtcNow.ToString("O") +} +[System.IO.File]::WriteAllText( + $buildInfoPath, + ($buildInfo | ConvertTo-Json -Depth 4), + [System.Text.UTF8Encoding]::new($false) +) + +$checksumTargets = @($msixPath, $uploadPath, $buildInfoPath) +[string[]] $checksumLines = $checksumTargets | ForEach-Object { + $hash = Get-FileHash -LiteralPath $_ -Algorithm SHA256 + $hash.Hash.ToLowerInvariant() + " " + [System.IO.Path]::GetFileName($_) +} +[System.IO.File]::WriteAllLines($checksumsPath, $checksumLines, [System.Text.Encoding]::ASCII) + +Write-Host "Created unsigned Microsoft Store artifacts:" +Write-Host " $msixPath" +Write-Host " $uploadPath" +Write-Host " $checksumsPath" diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 04cd882..9ce57a7 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -8,11 +8,13 @@ import gobley.gradle.GobleyHost import gobley.gradle.rust.targets.RustAndroidTarget import gobley.gradle.rust.targets.RustAppleMobileTarget import gobley.gradle.rust.targets.RustTarget +import gobley.gradle.Variant import org.gradle.api.DefaultTask import org.gradle.api.provider.ListProperty import org.gradle.api.tasks.Input import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.TaskAction +import org.gradle.jvm.tasks.Jar import org.jetbrains.kotlin.gradle.dsl.JvmTarget abstract class VerifyHostCargoTaskSelection : DefaultTask() { @@ -37,6 +39,17 @@ plugins { alias(libs.plugins.kotlinAtomicfu) } +val appVersion = providers.gradleProperty("vnidrop.version").get() +val desktopRustVariant = providers.gradleProperty("vnidrop.desktop.rustVariant") + .map { value -> + when (value.trim().lowercase()) { + "debug" -> Variant.Debug + "release" -> Variant.Release + else -> error("vnidrop.desktop.rustVariant must be either debug or release") + } + } + .orElse(Variant.Debug) + // Compile-time switches (gradle.properties or -P…). // included=false: no Share-diagnostics toggle, no telemetry/crash auto-upload stack. // endpoint/key both empty: transport is NoOp (safe default until Cloudflare is deployed). @@ -185,6 +198,7 @@ val hostCargoTargets = buildSet { cargo { packageDirectory = layout.projectDirectory.dir("../crates/vnidrop") publishJvmArtifacts = true + jvmVariant.set(desktopRustVariant) androidTargetsToBuild.set(setOf(RustAndroidTarget.Arm64, RustAndroidTarget.X64)) builds.jvm { variants { @@ -219,9 +233,15 @@ cargo { uniffi { generateFromLibrary { namespace = "vnidrop" + build.set(GobleyHost.current.rustTarget) + variant.set(desktopRustVariant) } } +tasks.named("jvmJar") { + manifest.attributes["Implementation-Version"] = appVersion +} + val verifyHostCargoTaskSelection = tasks.register( "verifyHostCargoTaskSelection" ) { From afa593b6db18bb3a2ffc073bffff481dc64b8442 Mon Sep 17 00:00:00 2001 From: Hammed Abass Date: Thu, 16 Jul 2026 22:52:24 +0200 Subject: [PATCH 3/4] fix(ci): use available Temurin release version --- .github/workflows/windows-store.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows-store.yml b/.github/workflows/windows-store.yml index 357f313..b6024b3 100644 --- a/.github/workflows/windows-store.yml +++ b/.github/workflows/windows-store.yml @@ -53,7 +53,7 @@ jobs: uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: temurin - java-version: "21.0.11+10" + java-version: "21.0.11+10.0.LTS" - name: Set up Gradle uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0 From 32c27343785b916699bfa8a26473c0cdd26e8eb0 Mon Sep 17 00:00:00 2001 From: Hammed Abass Date: Thu, 16 Jul 2026 23:11:32 +0200 Subject: [PATCH 4/4] fix(ci): pass named MSIX build arguments --- .github/workflows/windows-store.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/windows-store.yml b/.github/workflows/windows-store.yml index b6024b3..4192e79 100644 --- a/.github/workflows/windows-store.yml +++ b/.github/workflows/windows-store.yml @@ -130,11 +130,11 @@ jobs: - name: Create and validate Store package shell: pwsh run: | - $arguments = @( - "-Version", "${{ steps.version.outputs.app }}" - "-AppImage", ".\desktopApp\build\compose\binaries\main-release\app\VniDrop" - "-OutputDirectory", ".\build\release\windows" - ) + $arguments = @{ + Version = "${{ steps.version.outputs.app }}" + AppImage = ".\desktopApp\build\compose\binaries\main-release\app\VniDrop" + OutputDirectory = ".\build\release\windows" + } & .\packaging\windows\build-msix.ps1 @arguments - name: Upload Store artifacts