Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use rcodesign for notarization without requiring xcode #278

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
*
!src/main/docker/hashes.txt
!target/*-runner
!target/*-runner.jar
!target/lib/*
!target/lib/*
!target/quarkus-app/*
23 changes: 23 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
version: '3.9'
services:
application:
build:
context: .
dockerfile: ./src/main/docker/Dockerfile.jvm
ports:
- 8080:8080
environment:
- NOTARIZATION_APPLEAPI_KEYFILE=/var/run/secrets/apple-api.json
volumes:
- ./config/application/apple-api.json:/var/run/secrets/apple-api.json
deploy:
restart_policy:
condition: on-failure
max_attempts: 3
resources:
limits:
cpus: '0.5'
memory: 256M
reservations:
cpus: '0.001'
memory: 192M
34 changes: 34 additions & 0 deletions src/main/docker/Dockerfile.jvm
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#
# Based on a base image defined in the EF dockerfile project under https://github.com/EclipseFdn/dockerfiles/blob/master/java-api-base/Dockerfile.
#
# This image centralizes the base image version as well as any security patches to reduce the need to update all APIs manually in case of vulnerabilities or minor updates.
#
FROM eclipsefdn/java-api-base:j17-openjdk

# Install curl.
RUN microdnf --setopt=tsflags=nodocs install -y gzip

WORKDIR /deployments/bin

# Download apple-codesign tool and verify its hash
COPY src/main/docker/hashes.txt /deployments/bin/

ENV APPLE_CODESIGN_VERSION "0.26.0"
ENV APPLE_CODESIGN_ARCHIVE "apple-codesign-${APPLE_CODESIGN_VERSION}.tar.gz"

RUN curl -L -o ${APPLE_CODESIGN_ARCHIVE} "https://github.com/indygreg/apple-platform-rs/releases/download/apple-codesign%2F${APPLE_CODESIGN_VERSION}/apple-codesign-$APPLE_CODESIGN_VERSION-x86_64-unknown-linux-musl.tar.gz" \
&& sha256sum -c hashes.txt \
&& tar xzf ${APPLE_CODESIGN_ARCHIVE} --strip-components=1 \
&& rm -f ${APPLE_CODESIGN_ARCHIVE} \
&& chmod a+x rcodesign

ENV PATH "${PATH}:/deployments/bin"

# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=185 target/quarkus-app/*.jar /deployments/
COPY --chown=185 target/quarkus-app/app/ /deployments/app/
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/

EXPOSE 8080
USER 185
1 change: 1 addition & 0 deletions src/main/docker/hashes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cc2458901b2e93e21f1a4cc19ecc19a71dc2867d4d5f3f974091dac9ee536b1c apple-codesign-0.26.0.tar.gz
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@
import java.util.Comparator;
import java.util.stream.Stream;

import io.quarkus.runtime.Quarkus;
import io.quarkus.runtime.configuration.ConfigurationException;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;

import org.eclipse.cbi.ws.macos.notarization.execution.NotarizationCredentials;
import org.eclipse.cbi.ws.macos.notarization.execution.NotarizationTool;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -35,7 +39,15 @@ public class ApplicationLifecycle {
@ConfigProperty(name = "notarization.cache.uploadedFiles", defaultValue = "/tmp/macos-notarization-service/pending-files")
String pendingFiles;

@Inject
NotarizationTool notarizationTool;

@Inject
NotarizationCredentials notarizationCredentials;

void onStart(@Observes StartupEvent ev) throws IOException {
validateNotarizationCredentials();

Path pendingFilesPath = Paths.get(pendingFiles);

if (!Files.isDirectory(pendingFilesPath)) {
Expand All @@ -50,6 +62,13 @@ void onStart(@Observes StartupEvent ev) throws IOException {
}
}

private void validateNotarizationCredentials() {
if (!notarizationTool.validate(notarizationCredentials)) {
Quarkus.asyncExit(1);
Quarkus.waitForExit();
}
}

void onStop(@Observes ShutdownEvent ev) {
LOGGER.info("The application is stopping...");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledExecutorService;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.ws.rs.*;
Expand All @@ -28,8 +27,10 @@
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.ResponseBuilder;

import org.eclipse.cbi.ws.macos.notarization.execution.*;
import org.eclipse.cbi.ws.macos.notarization.execution.result.NotarizationInfoResult;
import org.eclipse.cbi.ws.macos.notarization.execution.result.NotarizerResult;
import org.eclipse.cbi.ws.macos.notarization.request.*;
import org.eclipse.cbi.ws.macos.notarization.xcrun.common.*;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
import org.slf4j.Logger;
Expand All @@ -45,9 +46,15 @@ public class NotarizationService {
@Inject
NotarizationCache cache;

@Inject
NotarizationCredentials notarizationCredentials;

@Inject
NotarizationTool notarizationTool;

@Inject
StaplerTool staplerTool;

@Inject
@Named("macos-notarization-service-pool")
ScheduledExecutorService executor;
Expand All @@ -56,18 +63,6 @@ public class NotarizationService {
@ConfigProperty(name = "notarization.cache.uploadedFiles", defaultValue = "/tmp/macos-notarization-service/pending-files")
String pendingFilesPath;

@Inject
@ConfigProperty(name = "notarization.appleid.password")
String appleIDPassword;

@Inject
@ConfigProperty(name = "notarization.appleid.username")
String appleIDUsername;

@Inject
@ConfigProperty(name = "notarization.appleid.teamid")
String appleIDTeamID;

@Inject
@ConfigProperty(name = "notarization.upload.timeout", defaultValue = "PT60M")
Duration uploadTimeout;
Expand Down Expand Up @@ -165,9 +160,7 @@ private NotarizationStatusWithUUID notarize(MultipartFormDataInputWrapper formDa
requestBuilder.notarizer(() ->
Notarizer.builder()
.primaryBundleId(options.primaryBundleId())
.appleIDUsername(appleIDUsername)
.appleIDPassword(appleIDPassword)
.appleIDTeamID(appleIDTeamID)
.credentials(notarizationCredentials)
.fileToNotarize(fileToNotarize)
.uploadTimeout(uploadTimeout)
.tool(notarizationTool)
Expand All @@ -176,9 +169,7 @@ private NotarizationStatusWithUUID notarize(MultipartFormDataInputWrapper formDa

requestBuilder.notarizationInfo((NotarizerResult r) ->
NotarizationInfo.builder()
.appleIDUsername(appleIDUsername)
.appleIDPassword(appleIDPassword)
.appleIDTeamID(appleIDTeamID)
.credentials(notarizationCredentials)
.appleRequestUUID(r.appleRequestUUID())
.pollingTimeout(infoPollingTimeout)
.tool(notarizationTool)
Expand All @@ -191,6 +182,7 @@ private NotarizationStatusWithUUID notarize(MultipartFormDataInputWrapper formDa
Stapler.builder()
.fileToStaple(fileToNotarize)
.staplingTimeout(staplingTimeout)
.tool(staplerTool)
.build()
.stapleFailsafe(staplingMaxAttempts, staplingMinBackOffDelay, staplingMaxBackOffDelay)));
}
Expand Down
20 changes: 17 additions & 3 deletions src/main/java/org/eclipse/cbi/ws/macos/notarization/Producer.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import org.eclipse.cbi.ws.macos.notarization.xcrun.common.NotarizationTool;
import org.eclipse.cbi.ws.macos.notarization.xcrun.notarytool.NotarytoolNotarizer;
import org.eclipse.cbi.ws.macos.notarization.execution.NotarizationTool;
import org.eclipse.cbi.ws.macos.notarization.execution.StaplerTool;
import org.eclipse.cbi.ws.macos.notarization.execution.generic.RustNotarizer;
import org.eclipse.cbi.ws.macos.notarization.execution.generic.RustStapler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -46,6 +48,18 @@ public NotarizationTool produceNotarizationTool() {
// OkHttpClient httpClient = new OkHttpClient.Builder().callTimeout(Duration.ofSeconds(30)).build();
//return new AltoolNotarizer(httpClient);

return new NotarytoolNotarizer();
// for notarytool:
//return new NotarytoolNotarizer();

return new RustNotarizer();
}

@Produces
@ApplicationScoped
public StaplerTool produceStaplerTool() {
// for running on macos:
//return new XcrunStapler();

return new RustStapler();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*******************************************************************************
* Copyright (c) 2023 Eclipse Foundation and others.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License 2.0
* which is available at http://www.eclipse.org/legal/epl-v20.html
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.cbi.ws.macos.notarization.execution;

import io.quarkus.runtime.Startup;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.cbi.ws.macos.notarization.NotarizationService;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Optional;

@Startup
@ApplicationScoped
public class NotarizationCredentials {
private static final Logger LOGGER = LoggerFactory.getLogger(NotarizationCredentials.class);

@Inject
@ConfigProperty(name = "notarization.appleid.password")
private Optional<String> appleIDPassword;

@Inject
@ConfigProperty(name = "notarization.appleid.username")
private Optional<String> appleIDUsername;

@Inject
@ConfigProperty(name = "notarization.appleid.teamid")
private Optional<String> appleIDTeamID;

@Inject
@ConfigProperty(name = "notarization.appleapi.keyfile")
private Optional<String> appleApiKeyFile;

public boolean requireUsername() {
if (appleIDUsername.isEmpty()) {
LOGGER.error("required configuration value 'notarization.appleid.username' is missing");
return false;
} else {
return true;
}
}

public boolean requirePassword() {
if (appleIDUsername.isEmpty()) {
LOGGER.error("required configuration value 'notarization.appleid.password' is missing");
return false;
} else {
return true;
}
}

public boolean requireTeamID() {
if (appleIDUsername.isEmpty()) {
LOGGER.error("required configuration value 'notarization.appleid.teamid' is missing");
return false;
} else {
return true;
}
}

public boolean requireAppleApiKeyFile() {
if (appleApiKeyFile.isEmpty()) {
LOGGER.error("required configuration value 'notarization.appleapi.keyfile' is missing");
return false;
} else {
return true;
}
}

public String getUsername() {
return appleIDUsername.get();
}

public boolean hasPassword() {
return appleIDPassword.isPresent();
}

public String getPassword() {
return appleIDPassword.get();
}

public String getTeamID() {
return appleIDTeamID.get();
}

public String getAppleApiKeyFile() {
return appleApiKeyFile.get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
* which is available at http://www.eclipse.org/legal/epl-v20.html
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.cbi.ws.macos.notarization.xcrun.common;
package org.eclipse.cbi.ws.macos.notarization.execution;

import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.ExecutionException;

import org.eclipse.cbi.ws.macos.notarization.execution.result.NotarizationInfoResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -21,9 +22,7 @@

@RecordBuilder
public record NotarizationInfo(
String appleIDUsername,
String appleIDPassword,
String appleIDTeamID,
NotarizationCredentials credentials,
String appleRequestUUID,
Duration pollingTimeout,
NotarizationTool tool) {
Expand Down Expand Up @@ -65,6 +64,6 @@ public NotarizationInfoResult retrieveInfoFailsafe(Duration maxTotalDuration,
.onFailure(l ->
LOGGER.error("Fail to fetch notarization info retrieval attempt #" + l.getAttemptCount() + ", cause: " +
l.getFailure().getMessage() + ", elapsed time: " + l.getElapsedTime(), l.getFailure()))
.get(() -> tool().retrieveInfo(appleIDUsername(), appleIDPassword(), appleIDTeamID(), appleRequestUUID(), pollingTimeout()));
.get(() -> tool().retrieveInfo(credentials(), appleRequestUUID(), pollingTimeout()));
}
}
Loading
Loading