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

Replace fgdc2iso service with CLI invocation #2917

Closed
7 of 8 tasks
mogul opened this issue Mar 1, 2021 · 19 comments
Closed
7 of 8 tasks

Replace fgdc2iso service with CLI invocation #2917

mogul opened this issue Mar 1, 2021 · 19 comments
Assignees

Comments

@mogul
Copy link
Contributor

mogul commented Mar 1, 2021

User Story

In order to remove moving parts and reduce the compliance overhead of operating data.gov, the data.gov team wants to convert geometadata formats during harvesting using a CLI call instead of calling a separate web service.

Acceptance Criteria

  • GIVEN I have checked out the ckanext-geodatagov plugin repository
    WHEN I run the tests
    THEN I see a test for conversion of FGDC/RSE to ISO 19115-2 listed
    AND the test passes
  • WHEN I search the datagov-deploy repository's issue tracker for issues labeled component/fgdc2iso
    AND I search the datagov-deploy repository's issue tracker for issues mentioning fgdc2iso in the title
    THEN I find only closed issues
  • WHEN I look at the catalog-fgdc2iso repository on GitHub
    THEN I see the repository is archived, with a note that it has been replaced
  • GIVEN I am logged into cloud.gov
    AND I have run cf t -o gsa-datagov
    WHEN I run cf t -s development ; cf apps | grep fgdc2iso
    AND I run cf t -s staging ; cf apps | grep fgdc2iso
    AND I run cf t -s prod ; cf apps | grep fgdc2iso
    THEN I do not see any results.

Background

Here's the results of the research story that prompted this issue.

Security Considerations (required)

This change will add the JRE runtime to the catalog.data.gov application in order to allow for calling a .jar from the CLI. It will also remove the need for an entire webservice, catalog-fgdc2iso, and communications with that service. The net result will be a much simpler system with fewer potentially-exposed surfaces to protect

Include a test for XXE handling if applicable (#3246).

Sketch

Here's the code that calls fgdc2iso now, and the Jython code that actually does the transform now.

  • Ensure that Saxon-Java/HE is and the JRE are installed in our catalog.data.gov Docker images, and that the JAVA_HOME environment variable is set properly. Here's an Alpine Dockerfile that demonstrates installing Saxon-Java/HE. Probably better than muddling through on Alpine would be to switch to using an Ubuntu-based CKAN image for catalog.data.gov, then using methods similar to the plan for cloud.gov (see below) to add the JRE and Saxon via apt install.
  • Add a test for converting between FGDC/RSE to ISO 19115-2 (using the fixture here)
  • Replace the code referenced above with a call out to java net.sf.saxon.Transform -s:[source] -xsl:[stylesheet] -o:[output]
  • Ensure that the JRE and Saxon-Java/HE are installed in the catalog.data.gov application when it's staged on cloud.gov. We can install the java runtime using the apt-buildpack, and also use that same apt.yaml file to install Saxon-HE/Java from a PPA.
@mogul mogul changed the title Replace fgdc2iso service request with CLI invocation Replace fgdc2iso service with CLI invocation Mar 1, 2021
@mogul
Copy link
Contributor Author

mogul commented Mar 1, 2021

Can someone add pointers needed for getting the JRE and Saxon-Java/HE .debs included in the Ansible playbook to the sketch above?

@jbrown-xentity jbrown-xentity mentioned this issue Mar 10, 2021
1 task
adborden added a commit to GSA/catalog-fgdc2iso that referenced this issue Mar 31, 2021
Currently we're not running harvesters and looking to save some memory quota.
Also, we're planning to [replace the fgdc2iso service][1].

[1]: GSA/data.gov#2917
@jbrown-xentity jbrown-xentity self-assigned this Oct 7, 2021
@jbrown-xentity
Copy link
Contributor

jbrown-xentity commented Oct 8, 2021

I was able to successfully add java to the current catalog docker image via apk; add the necessary saxon he jar file, and run a command to transform the current FGDC/CSDGM example in catalog-fgdc2iso into ISO!
All this was done via command line and testing, will move to set the docker image up correctly and then create a PR demonstrating this is possible. Then we will add a test case for FGDC metadata as a harvest source to validate.
The command to successfully transform: java -cp /usr/lib/jvm/java-11-openjdk/saxon/saxon.jar net.sf.saxon.Transform -s:/srv/app/csdgm_sample.xml -xsl:/csdgm2iso.xslt -o:/srv/app/iso_t_sample.xml

@jbrown-xentity
Copy link
Contributor

I added a test to geodatagov, which is failing. The error has to do with the encoding of the xml file. I based the new transformation return on the old service transformation return. Something must be happening with the way the server returns/encodes the result.
The error the ISO parser gives is Unicode strings with encoding declaration are not supported. Please use bytes input or XML fragments without declaration.
Not sure where to go from here, have already tried a lot of debugging around encoding/decoding the stream from the transformed file.

@jbrown-xentity
Copy link
Contributor

By removing the encoding parameter in the ISO output, we were able to get the transformation service working again. See PR for details.

Also, removed all FGDC deployments on cloud.gov:
image

@jbrown-xentity
Copy link
Contributor

CloudFoundry doesn't like the java installation via apt...
When I install the jdk and try to run the transform manually via ssh, I get a nasty stack trace (see below).
Googling involved looking at the java.security file, which was a soft link to a path that didn't exist. It was pointing to /etc, when it needed to point at /home/vcap/deps/0/apt/etc. Moving the pointer didn't seem to do much, so I believe the whole installation is pretty misconfigured and will need lost of custom fixes and/or debugging... :(

vcap@9c4495f8-ba0d-4e02-7609-345b:~$ java -cp saxon.jar net.sf.saxon.Transform -s:/home/vcap/deps/1/src/ckanext-geodatagov/ckanext/geodatagov/tests/data-samples/waf-fgdc/fgdc-csdgm_sample.xml -xsl:/home/vcap/deps/1/src/ckanext-geodatagov/ckanext/geodatagov/harvesters/fgdcrse2iso19115-2.xslt -o:iso_sample.xml
Exception in thread "main" java.lang.ExceptionInInitializerError
        at java.base/javax.crypto.Cipher.getInstance(Cipher.java:540)
        at java.base/sun.security.ssl.JsseJce.getCipher(JsseJce.java:185)
        at java.base/sun.security.ssl.SSLCipher.isTransformationAvailable(SSLCipher.java:483)
        at java.base/sun.security.ssl.SSLCipher.<init>(SSLCipher.java:472)
        at java.base/sun.security.ssl.SSLCipher.<clinit>(SSLCipher.java:81)
        at java.base/sun.security.ssl.CipherSuite.<clinit>(CipherSuite.java:67)
        at java.base/sun.security.ssl.SSLContextImpl.getApplicableSupportedCipherSuites(SSLContextImpl.java:348)
        at java.base/sun.security.ssl.SSLContextImpl$AbstractTLSContext.<clinit>(SSLContextImpl.java:580)
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:315)
        at java.base/java.security.Provider$Service.getImplClass(Provider.java:1918)
        at java.base/java.security.Provider$Service.newInstance(Provider.java:1894)
        at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:236)
        at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:164)
        at java.base/javax.net.ssl.SSLContext.getInstance(SSLContext.java:168)
        at java.base/javax.net.ssl.SSLContext.getDefault(SSLContext.java:99)
        at java.base/javax.net.ssl.SSLSocketFactory.getDefault(SSLSocketFactory.java:123)
        at java.base/javax.net.ssl.HttpsURLConnection.getDefaultSSLSocketFactory(HttpsURLConnection.java:335)
        at java.base/javax.net.ssl.HttpsURLConnection.<init>(HttpsURLConnection.java:292)
        at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.<init>(HttpsURLConnectionImpl.java:100)
        at java.base/sun.net.www.protocol.https.Handler.openConnection(Handler.java:62)
        at java.base/sun.net.www.protocol.https.Handler.openConnection(Handler.java:57)
        at java.base/java.net.URL.openConnection(URL.java:1099)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:650)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:1398)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startDTDEntity(XMLEntityManager.java:1364)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.setInputSource(XMLDTDScannerImpl.java:257)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.dispatch(XMLDocumentScannerImpl.java:1152)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.next(XMLDocumentScannerImpl.java:1040)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:943)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:605)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:534)
        at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:888)
        at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:824)
        at java.xml/com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
        at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1216)
        at java.xml/com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:635)
        at net.sf.saxon.event.Sender.sendSAXSource(Sender.java:435)
        at net.sf.saxon.event.Sender.send(Sender.java:167)
        at net.sf.saxon.Configuration.buildDocumentTree(Configuration.java:4236)
        at net.sf.saxon.s9api.DocumentBuilder.build(DocumentBuilder.java:357)
        at net.sf.saxon.Transform.processFile(Transform.java:1260)
        at net.sf.saxon.Transform.doTransform(Transform.java:815)
        at net.sf.saxon.Transform.main(Transform.java:80)
Caused by: java.lang.SecurityException: Can not initialize cryptographic mechanism
        at java.base/javax.crypto.JceSecurity.<clinit>(JceSecurity.java:120)
        ... 45 more
Caused by: java.lang.SecurityException: Couldn't parse jurisdiction policy files in: unlimited
        at java.base/javax.crypto.JceSecurity.setupJurisdictionPolicies(JceSecurity.java:357)
        at java.base/javax.crypto.JceSecurity$1.run(JceSecurity.java:111)
        at java.base/javax.crypto.JceSecurity$1.run(JceSecurity.java:108)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at java.base/javax.crypto.JceSecurity.<clinit>(JceSecurity.java:107)
        ... 45 more

@mogul
Copy link
Contributor Author

mogul commented Oct 12, 2021

You might still need to include the java-buildpack in the buildpack chain a proper JVM installed and callable as java at the command-line.

@mogul
Copy link
Contributor Author

mogul commented Oct 12, 2021

Maybe not...

The Java Buildpack is not designed to provide a JRE to an arbitrary application. It was instead designed to run Java applications, providing JREs to them as necessary. As the contribution behavior is not a goal, this buildpack will never be updated to do so.

😬

@mogul
Copy link
Contributor Author

mogul commented Oct 12, 2021

Googling involved looking at the java.security file, which was a soft link to a path that didn't exist. It was pointing to /etc, when it needed to point at /home/vcap/deps/0/apt/etc. Moving the pointer didn't seem to do much, so I believe the whole installation is pretty misconfigured and will need lost of custom fixes and/or debugging... :(

Looks like someone has summarized concisely what needs to be done at SO.

@jbrown-xentity
Copy link
Contributor

I did see that, although my experience was not the same. Possibly because I'm installing the latest known version to work with saxon transformation (11.x). I was able to use ls -lR /home/vcap/deps/0/apt/usr/lib/jvm/ | grep ^l to find all instances of soft links that java uses, there are 21 that point to something like /etc/java-11-openjdk which should point to /home/vcap/deps/0/etc/java-11-openjdk. Will investigate trying java-8 (per example) or updating links to the correct directory...

@jbrown-xentity
Copy link
Contributor

Tried both installing java 8 (and other versions, same error) and changing soft links (different error). This is definitely an issue with the install. Going to try to install java via apt in ubuntu image and see if the saxon file can be run...

@jbrown-xentity
Copy link
Contributor

Status: adding the cleancache: true to the apt.yml file seems to have cleaned up old openjdk default and openjdk 8 files; will keep in the future. Not sure why a new push left those files there.
A file was missed in linking to cacerts in the ln re-linking, that was re-linked.
A new error is occurring. Still seems related to java certs of some kind. When I tried to check the certs with keytool -list -cacerts, I get keytool error: java.security.KeyStoreException: This keystore does not support probing and must be loaded with a specified type, which is the default error (see here). When you try to specify the type, you get keytool error: java.lang.IllegalArgumentException: The -keystore or -storetype option cannot be used with the -cacerts option.
I was lead to look at keytool because of the java command output failure:

java -cp /home/vcap/app/saxon.jar net.sf.saxon.Transform -s:/home/vcap/deps/1/src/ckanext-geodatagov/ckanext/geodatagov/tests/data-samples/waf-fgdc/fgdc-csdgm_sample.xml -xsl:/home/vcap/deps/1/src/ckanext-geodatagov/ckanext/geodatagov/harvesters/fgdcrse2iso19115-2.xslt -o:iso_sample.xml
I/O error reported by XML parser processing file:/home/vcap/deps/1/src/ckanext-geodatagov/ckanext/geodatagov/tests/data-samples/waf-fgdc/fgdc-csdgm_sample.xml: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: sun.security.ssl.SSLContextImpl$DefaultSSLContext)

@jbrown-xentity
Copy link
Contributor

We tested installing default-jre-headless with apt via docker run --rm -i cloudfoundry/cflinuxfs3 /bin/bash. We can confirm the blocker with the full java installation is the same as found here: because /usr/share/man/* is removed, java installation fails (tries to insert into /usr/share/man/man1/).

@mogul
Copy link
Contributor Author

mogul commented Oct 15, 2021

I believe I've found a way we can precede the installation of the package with the mkdir -p /usr/share/man/man1 command, using equivs-build.

equivs-build is a program that creates Debian packages which can be used to inform dpkg about locally installed packages and their dependencies. Also empty packages that just require other packages can be created with equivs. These can be used as "profile" packages which just mark other ones for installation.

I suspect we can create a "profile" .deb file that marks default-jre-headless for install and includes a preinst script that runs the mkdir command. Then we just publish the .deb in a release in the catalog-app repository and refer to it from the apt.yml file:

---
packages:
- https://github.com/GSA/catalog.data.gov/releases/download/jre-shim-deb/default-jre-headless-fixer.deb

@mogul
Copy link
Contributor Author

mogul commented Oct 15, 2021

(If equivs-build doesn't work, then we can just make a full-fledged .deb package that does the same thing with more elbow grease and unnecessary ramp-up on how to make a .deb.)

@mogul
Copy link
Contributor Author

mogul commented Oct 15, 2021

I take it back; it looks like we can't use a "profile" package to do this because of when preinst scripts get called (emphasis mine):

The package will not yet be unpacked, so the preinst script cannot rely on any files included in its package. Only essential packages and pre-dependencies (Pre-Depends) may be assumed to be available. Pre-dependencies will have been configured at least once, but at the time the preinst is called they may only be in an “Unpacked” or “Half-Configured” state if a previous version of the pre-dependency was completely configured and has not been removed since then.

The language here suggests that we can't rely on preinst being called before apt attempts to install and configure default-jre-headless.

However, the answer is still pretty simple... The package we create should just include the preinst command and not depend on anything else. Then we install the two packages:

---
packages: 
- https://github.com/GSA/catalog.data.gov/releases/download/cflinuxfs3-fhs-fixup/cflinuxfs3-fhs-fixup.deb
- default-jre-headless

(I looked up how apt install decides what order it should install packages when you specify multiple. It does dependencies first, in alphabetical order, then the actual specified, in alphabetical order. That means as long as our package name is alphabetically before default-jre-headless then we can be confident it will be installed first.)

@mogul
Copy link
Contributor Author

mogul commented Oct 15, 2021

Here's a little present for you, @jbrown-xentity... It should probably get broken out into a top-level repository since it can be useful to people using CF and the apt-buildpack generally, but I'll leave that as an exercise for you. 😜

[Edited to add: Attention Google searchers, this /usr/share/man/man1 observation turned out to be a read herring! It does indeed prevent apt install default-jre-headless from finishing in a cflinuxfs3 Docker container, but that's unrelated to how the apt-buildpack operates. See this discussion in the CF Slack for more details.]

@mogul
Copy link
Contributor Author

mogul commented Oct 15, 2021

You can install saxon.jar using Ubuntu packages rather than curling it from Maven repositories. It's at /usr/share/java/saxon.jar after you install the libsaxon-java package.

@mogul
Copy link
Contributor Author

mogul commented Oct 19, 2021

Progress update:

We can get the java CLI callable just by setting the JAVA_HOME and amending the path in the .profile:

#!/bin/sh
export JAVA_HOME=/home/vcap/deps/0/apt/usr/lib/jvm/java-11-openjdk-amd64
export PATH=$PATH:$JAVA_HOME/bin

After this, java -version works fine.

However, that's not enough because when you run the actual saxon transform it flames out:

[EXPAND] java barfs on broken links in install
$ java -cp ${saxon} net.sf.saxon.Transform -s:fgdc-csdgm_sample.xml -xsl:fgdcrse2iso19115-2.xslt -o:iso_sample.xmlException in thread "main" java.lang.ExceptionInInitializerError
        at java.base/javax.crypto.Cipher.getInstance(Cipher.java:540)
        at java.base/sun.security.ssl.JsseJce.getCipher(JsseJce.java:185)
        at java.base/sun.security.ssl.SSLCipher.isTransformationAvailable(SSLCipher.java:483)
        at java.base/sun.security.ssl.SSLCipher.<init>(SSLCipher.java:472)
        at java.base/sun.security.ssl.SSLCipher.<clinit>(SSLCipher.java:81)
        at java.base/sun.security.ssl.CipherSuite.<clinit>(CipherSuite.java:67)
        at java.base/sun.security.ssl.SSLContextImpl.getApplicableSupportedCipherSuites(SSLContextImpl.java:348)
        at java.base/sun.security.ssl.SSLContextImpl$AbstractTLSContext.<clinit>(SSLContextImpl.java:580)
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:315)
        at java.base/java.security.Provider$Service.getImplClass(Provider.java:1918)
        at java.base/java.security.Provider$Service.newInstance(Provider.java:1894)
        at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:236)
        at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:164)
        at java.base/javax.net.ssl.SSLContext.getInstance(SSLContext.java:168)
        at java.base/javax.net.ssl.SSLContext.getDefault(SSLContext.java:99)
        at java.base/javax.net.ssl.SSLSocketFactory.getDefault(SSLSocketFactory.java:123)
        at java.base/javax.net.ssl.HttpsURLConnection.getDefaultSSLSocketFactory(HttpsURLConnection.java:335)
        at java.base/javax.net.ssl.HttpsURLConnection.<init>(HttpsURLConnection.java:292)
        at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.<init>(HttpsURLConnectionImpl.java:100)
        at java.base/sun.net.www.protocol.https.Handler.openConnection(Handler.java:62)
        at java.base/sun.net.www.protocol.https.Handler.openConnection(Handler.java:57)
        at java.base/java.net.URL.openConnection(URL.java:1099)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:650)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:1398)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startDTDEntity(XMLEntityManager.java:1364)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.setInputSource(XMLDTDScannerImpl.java:257)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.dispatch(XMLDocumentScannerImpl.java:1152)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.next(XMLDocumentScannerImpl.java:1040)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:943)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:605)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
        at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:534)
        at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:888)
        at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:824)
        at java.xml/com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
        at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1216)
        at java.xml/com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:635)
        at net.sf.saxon.event.Sender.sendSAXSource(Sender.java:435)
        at net.sf.saxon.event.Sender.send(Sender.java:167)
        at net.sf.saxon.Configuration.buildDocumentTree(Configuration.java:4236)
        at net.sf.saxon.s9api.DocumentBuilder.build(DocumentBuilder.java:357)
        at net.sf.saxon.Transform.processFile(Transform.java:1260)
        at net.sf.saxon.Transform.doTransform(Transform.java:815)
        at net.sf.saxon.Transform.main(Transform.java:80)
Caused by: java.lang.SecurityException: Can not initialize cryptographic mechanism
        at java.base/javax.crypto.JceSecurity.<clinit>(JceSecurity.java:120)
        ... 45 more
Caused by: java.lang.SecurityException: Couldn't parse jurisdiction policy files in: unlimited
        at java.base/javax.crypto.JceSecurity.setupJurisdictionPolicies(JceSecurity.java:357)
        at java.base/javax.crypto.JceSecurity$1.run(JceSecurity.java:111)
        at java.base/javax.crypto.JceSecurity$1.run(JceSecurity.java:108)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at java.base/javax.crypto.JceSecurity.<clinit>(JceSecurity.java:107)
        ... 45 more

This is because the OpenJDK installation ships with a bunch of symlinks that point to /etc. The symlinks are broken because the apt-buildpack doesn't run as root and doesn't install the expected stuff at /etc... They are installed at /home/vcap/deps/0/apt/etc instead. So we need to fix up those links. This one-liner works:

find /home/vcap/deps/0 -xtype l -exec bash -c 'target="$(readlink "{}")"; link="{}"; target="$(echo "$target" | sed "s+^/etc+/home/vcap/deps/0/apt/etc+")"; ln -Tfs "$target" "$link"' \;

That fixes the 25 broken links to point to /home/vcap/deps/0/apt/etc instead of /etc. Now when we run the test command we get a different error:

$ java -cp ${saxon} net.sf.saxon.Transform -s:fgdc-csdgm_sample.xml -xsl:fgdcrse2iso19115-2.xslt -o:iso_sample.xml
I/O error reported by XML parser processing file:/home/vcap/app/fgdc-csdgm_sample.xml: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

It turns out there is still one broken link after that fix:

$ find /home/vcap/deps/0 -xtype l 
/home/vcap/deps/0/apt/usr/lib/jvm/java-11-openjdk-amd64/lib/security/cacerts
$ ls -alh /home/vcap/deps/0/apt/usr/lib/jvm/java-11-openjdk-amd64/lib/security/cacerts
lrwxrwxrwx 1 vcap vcap 48 Oct 19 04:19 /home/vcap/deps/0/apt/usr/lib/jvm/java-11-openjdk-amd64/lib/security/cacerts -> /home/vcap/deps/0/apt/etc/ssl/certs/java/cacerts
$ ls -lh /home/vcap/deps/0/apt/etc/ssl/certs/java/cacerts
ls: cannot access '/home/vcap/deps/0/apt/etc/ssl/certs/java/cacerts': No such file or directory

To properly start an SSL client connection, java needs a trust store pre-filled with the various root CAs that it should use to verify that certificates are legit. The trustAnchors parameter must be non-empty message refers to exactly that cacerts file, which normally symlinks to a system-wide /etc/ssl/certs/java/cacerts file which doesn't exist in this environment. With that file missing, no SSL connection will be successful.

To verify this was the problem I tried copying the /etc/ssl/certs/java/cacerts file from a cflinuxfs3:latest Docker container (after first running apt install default-jre-headless) into the CF application directory. Then I set a parameter to have java use that local file as the trustStore:

$ java -cp ${saxon}  -Djavax.net.ssl.trustStore=./cacerts net.sf.saxon.Transform -s:fgdc-csdgm_sample.xml -xsl:fgdcrse2iso19115-2.xslt -o:iso_sample.xml
vcap@9bb0681e-854f-4cdc-4a0c-623c:~$ head iso_sample.xml 
<?xml version="1.0" encoding="UTF-8"?>
<!--+########################################################################+-->
<!--+    This file was generated using an FGDC CSDGM to ISO19139 Transform   +-->
<!--+                                                                        +-->
<!--+ This is accomplished using an XML Style sheet that transforms metadata +-->
<!--+ conforming to the CSDGM to the ISO 19139.                              +-->
<!--#########################################################################+-->
<gmd:MD_Metadata xmlns:gco="http://www.isotc211.org/2005/gco"
                 xmlns:gmd="http://www.isotc211.org/2005/gmd"
                 xmlns:gmi="http://www.isotc211.org/2005/gmi"
[...]

SUCCESS! I did a little additional work and now the test command works after SSH'ing in and just sourcing .profile.

$ cf ssh bret-apttest 
vcap@9bb0681e-854f-4cdc-4a0c-623c:~$ /tmp/lifecycle/shell 
vcap@9bb0681e-854f-4cdc-4a0c-623c:~$ source .profile
vcap@9bb0681e-854f-4cdc-4a0c-623c:~$ java -cp ./saxon.jar net.sf.saxon.Transform -s:fgdc-csdgm_sample.xml -xsl:fgdcrse2iso19115-2.xslt -o:iso_sample.xml
vcap@9bb0681e-854f-4cdc-4a0c-623c:~$ echo $?
0
vcap@9bb0681e-854f-4cdc-4a0c-623c:~$ ls -l iso_sample.xml 
-rw-r--r-- 1 vcap vcap 40577 Oct 19 04:33 iso_sample.xml
vcap@9bb0681e-854f-4cdc-4a0c-623c:~$ file iso_sample.xml 
iso_sample.xml: XML 1.0 document, UTF-8 Unicode text, with very long lines

I pushed this working test to the features/fgdc2iso-integration branch.

Now the question is: Are we content with shipping our own cacerts file as part of the application? It's easy enough to regenerate the file with these commands, which can run during dev or during CI/CD:

$ docker run -v $PWD:$PWD -w $PWD -it --rm cloudfoundry/cflinuxfs3:latest bash
# apt update
# mkdir -p /usr/share/man/man1
# apt-get install ca-certificates-java -y
# cp /etc/ssl/certs/java/cacerts .
# exit

Here's a log of those commands in action:

[EXPAND]: Full log of generating cacerts
bmogilefsky@rocinante-w10:~/Documents/Code/apt-buildpack/fixtures/bret$ docker run -v $PWD:$PWD -w $PWD -it --rm cloudfoundry/cflinuxfs3:latest bash
root@0873d84aae90:/home/bmogilefsky/Documents/Code/apt-buildpack/fixtures/bret# apt update
Get:1 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB]
Get:2 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]
Get:3 http://archive.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]
Get:4 http://archive.ubuntu.com/ubuntu bionic/universe amd64 Packages [11.3 MB]
Get:5 http://archive.ubuntu.com/ubuntu bionic/main amd64 Packages [1344 kB]                                                         
Get:6 http://archive.ubuntu.com/ubuntu bionic/multiverse amd64 Packages [186 kB]                                                    
Get:7 http://archive.ubuntu.com/ubuntu bionic-updates/universe amd64 Packages [2211 kB]                                             
Get:8 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages [2808 kB]                                                 
Get:9 http://archive.ubuntu.com/ubuntu bionic-updates/multiverse amd64 Packages [34.4 kB]                                           
Get:10 http://archive.ubuntu.com/ubuntu bionic-security/universe amd64 Packages [1433 kB]                                           
Get:11 http://archive.ubuntu.com/ubuntu bionic-security/multiverse amd64 Packages [26.7 kB]                                         
Get:12 http://archive.ubuntu.com/ubuntu bionic-security/main amd64 Packages [2367 kB]                                               
Fetched 22.2 MB in 51s (432 kB/s)                                                                                                   
Reading package lists... Done
Building dependency tree       
Reading state information... Done
1 package can be upgraded. Run 'apt list --upgradable' to see it.
root@0873d84aae90:/home/bmogilefsky/Documents/Code/apt-buildpack/fixtures/bret# mkdir -p /usr/share/man/man1
root@0873d84aae90:/home/bmogilefsky/Documents/Code/apt-buildpack/fixtures/bret# apt-get install ca-certificates-java -y
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  java-common libasound2 libasound2-data libavahi-client3 libavahi-common-data libavahi-common3 libcups2 libnspr4 libnss3
  libpcsclite1 openjdk-11-jre-headless
Suggested packages:
  default-jre libasound2-plugins alsa-utils cups-common pcscd libnss-mdns fonts-dejavu-extra fonts-ipafont-gothic
  fonts-ipafont-mincho fonts-wqy-microhei | fonts-wqy-zenhei fonts-indic
The following NEW packages will be installed:
  ca-certificates-java java-common libasound2 libasound2-data libavahi-client3 libavahi-common-data libavahi-common3 libcups2
  libnspr4 libnss3 libpcsclite1 openjdk-11-jre-headless
0 upgraded, 12 newly installed, 0 to remove and 1 not upgraded.
Need to get 39.2 MB of archives.
After this operation, 177 MB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 java-common all 0.68ubuntu1~18.04.1 [14.5 kB]
Get:2 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 libavahi-common-data amd64 0.7-3.1ubuntu1.3 [22.2 kB]
Get:3 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 libavahi-common3 amd64 0.7-3.1ubuntu1.3 [21.6 kB]
Get:4 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 libavahi-client3 amd64 0.7-3.1ubuntu1.3 [25.2 kB]
Get:5 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 libcups2 amd64 2.2.7-1ubuntu2.8 [211 kB]
Get:6 http://archive.ubuntu.com/ubuntu bionic/main amd64 libnspr4 amd64 2:4.18-1ubuntu1 [112 kB]
Get:7 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 libnss3 amd64 2:3.35-2ubuntu2.12 [1220 kB]
Get:8 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 libasound2-data all 1.1.3-5ubuntu0.6 [38.5 kB]
Get:9 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 libasound2 amd64 1.1.3-5ubuntu0.6 [360 kB]
Get:10 http://archive.ubuntu.com/ubuntu bionic/main amd64 libpcsclite1 amd64 1.8.23-1 [21.3 kB]
Get:11 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 openjdk-11-jre-headless amd64 11.0.11+9-0ubuntu2~18.04 [37.2 MB]
Get:12 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 ca-certificates-java all 20180516ubuntu1~18.04.1 [12.2 kB]        
Fetched 39.2 MB in 1min 30s (436 kB/s)                                                                                              
Selecting previously unselected package java-common.
(Reading database ... 34509 files and directories currently installed.)
Preparing to unpack .../00-java-common_0.68ubuntu1~18.04.1_all.deb ...
Unpacking java-common (0.68ubuntu1~18.04.1) ...
Selecting previously unselected package libavahi-common-data:amd64.
Preparing to unpack .../01-libavahi-common-data_0.7-3.1ubuntu1.3_amd64.deb ...
Unpacking libavahi-common-data:amd64 (0.7-3.1ubuntu1.3) ...
Selecting previously unselected package libavahi-common3:amd64.
Preparing to unpack .../02-libavahi-common3_0.7-3.1ubuntu1.3_amd64.deb ...
Unpacking libavahi-common3:amd64 (0.7-3.1ubuntu1.3) ...
Selecting previously unselected package libavahi-client3:amd64.
Preparing to unpack .../03-libavahi-client3_0.7-3.1ubuntu1.3_amd64.deb ...
Unpacking libavahi-client3:amd64 (0.7-3.1ubuntu1.3) ...
Selecting previously unselected package libcups2:amd64.
Preparing to unpack .../04-libcups2_2.2.7-1ubuntu2.8_amd64.deb ...
Unpacking libcups2:amd64 (2.2.7-1ubuntu2.8) ...
Selecting previously unselected package libnspr4:amd64.
Preparing to unpack .../05-libnspr4_2%3a4.18-1ubuntu1_amd64.deb ...
Unpacking libnspr4:amd64 (2:4.18-1ubuntu1) ...
Selecting previously unselected package libnss3:amd64.
Preparing to unpack .../06-libnss3_2%3a3.35-2ubuntu2.12_amd64.deb ...
Unpacking libnss3:amd64 (2:3.35-2ubuntu2.12) ...
Selecting previously unselected package libasound2-data.
Preparing to unpack .../07-libasound2-data_1.1.3-5ubuntu0.6_all.deb ...
Unpacking libasound2-data (1.1.3-5ubuntu0.6) ...
Selecting previously unselected package libasound2:amd64.
Preparing to unpack .../08-libasound2_1.1.3-5ubuntu0.6_amd64.deb ...
Unpacking libasound2:amd64 (1.1.3-5ubuntu0.6) ...
Selecting previously unselected package libpcsclite1:amd64.
Preparing to unpack .../09-libpcsclite1_1.8.23-1_amd64.deb ...
Unpacking libpcsclite1:amd64 (1.8.23-1) ...
Selecting previously unselected package openjdk-11-jre-headless:amd64.
Preparing to unpack .../10-openjdk-11-jre-headless_11.0.11+9-0ubuntu2~18.04_amd64.deb ...
Unpacking openjdk-11-jre-headless:amd64 (11.0.11+9-0ubuntu2~18.04) ...
Selecting previously unselected package ca-certificates-java.
Preparing to unpack .../11-ca-certificates-java_20180516ubuntu1~18.04.1_all.deb ...
Unpacking ca-certificates-java (20180516ubuntu1~18.04.1) ...
Setting up libpcsclite1:amd64 (1.8.23-1) ...
Setting up libasound2-data (1.1.3-5ubuntu0.6) ...
Setting up java-common (0.68ubuntu1~18.04.1) ...
Setting up libnspr4:amd64 (2:4.18-1ubuntu1) ...
Setting up libasound2:amd64 (1.1.3-5ubuntu0.6) ...
Setting up libavahi-common-data:amd64 (0.7-3.1ubuntu1.3) ...
Setting up libnss3:amd64 (2:3.35-2ubuntu2.12) ...
Setting up libavahi-common3:amd64 (0.7-3.1ubuntu1.3) ...
Setting up libavahi-client3:amd64 (0.7-3.1ubuntu1.3) ...
Setting up libcups2:amd64 (2.2.7-1ubuntu2.8) ...
Setting up openjdk-11-jre-headless:amd64 (11.0.11+9-0ubuntu2~18.04) ...
update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/java to provide /usr/bin/java (java) in auto mode
update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/jjs to provide /usr/bin/jjs (jjs) in auto mode
update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/keytool to provide /usr/bin/keytool (keytool) in auto mode
update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/rmid to provide /usr/bin/rmid (rmid) in auto mode
update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/rmiregistry to provide /usr/bin/rmiregistry (rmiregistry) in auto mode
update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/pack200 to provide /usr/bin/pack200 (pack200) in auto mode
update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/unpack200 to provide /usr/bin/unpack200 (unpack200) in auto mode
update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/lib/jexec to provide /usr/bin/jexec (jexec) in auto mode
Setting up ca-certificates-java (20180516ubuntu1~18.04.1) ...
head: cannot open '/etc/ssl/certs/java/cacerts' for reading: No such file or directory
Adding debian:Buypass_Class_2_Root_CA.pem
Adding debian:Microsec_e-Szigno_Root_CA_2009.pem
Adding debian:XRamp_Global_CA_Root.pem
Adding debian:Certigna_Root_CA.pem
Adding debian:TrustCor_RootCert_CA-2.pem
Adding debian:Network_Solutions_Certificate_Authority.pem
Adding debian:VeriSign_Universal_Root_Certification_Authority.pem
Adding debian:Staat_der_Nederlanden_Root_CA_-_G3.pem
Adding debian:Entrust_Root_Certification_Authority_-_G4.pem
Adding debian:T-TeleSec_GlobalRoot_Class_3.pem
Adding debian:QuoVadis_Root_CA_1_G3.pem
Adding debian:Global_Chambersign_Root_-_2008.pem
Adding debian:Cybertrust_Global_Root.pem
Adding debian:AC_RAIZ_FNMT-RCM.pem
Adding debian:USERTrust_RSA_Certification_Authority.pem
Adding debian:SSL.com_EV_Root_Certification_Authority_RSA_R2.pem
Adding debian:CFCA_EV_ROOT.pem
Adding debian:D-TRUST_Root_Class_3_CA_2_EV_2009.pem
Adding debian:DigiCert_High_Assurance_EV_Root_CA.pem
Adding debian:DigiCert_Assured_ID_Root_CA.pem
Adding debian:GTS_Root_R4.pem
Adding debian:Go_Daddy_Root_Certificate_Authority_-_G2.pem
Adding debian:Actalis_Authentication_Root_CA.pem
Adding debian:Hongkong_Post_Root_CA_3.pem
Adding debian:GlobalSign_Root_CA_-_R3.pem
Adding debian:Security_Communication_Root_CA.pem
Adding debian:GTS_Root_R3.pem
Adding debian:TrustCor_ECA-1.pem
Adding debian:GlobalSign_ECC_Root_CA_-_R5.pem
Adding debian:Trustwave_Global_ECC_P256_Certification_Authority.pem
Adding debian:Amazon_Root_CA_2.pem
Adding debian:Certigna.pem
Adding debian:GlobalSign_Root_CA.pem
Adding debian:GlobalSign_ECC_Root_CA_-_R4.pem
Adding debian:COMODO_RSA_Certification_Authority.pem
Adding debian:DigiCert_Global_Root_G2.pem
Adding debian:SecureSign_RootCA11.pem
Adding debian:SZAFIR_ROOT_CA2.pem
Adding debian:Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.pem
Adding debian:GTS_Root_R2.pem
Adding debian:AffirmTrust_Premium_ECC.pem
Adding debian:Trustwave_Global_Certification_Authority.pem
Adding debian:SSL.com_Root_Certification_Authority_ECC.pem
Adding debian:DigiCert_Trusted_Root_G4.pem
Adding debian:NAVER_Global_Root_Certification_Authority.pem
Adding debian:Baltimore_CyberTrust_Root.pem
Adding debian:E-Tugra_Certification_Authority.pem
Adding debian:T-TeleSec_GlobalRoot_Class_2.pem
Adding debian:Certum_Trusted_Network_CA.pem
Adding debian:SwissSign_Gold_CA_-_G2.pem
Adding debian:Hongkong_Post_Root_CA_1.pem
Adding debian:Entrust_Root_Certification_Authority.pem
Adding debian:USERTrust_ECC_Certification_Authority.pem
Adding debian:emSign_ECC_Root_CA_-_G3.pem
Adding debian:Microsoft_ECC_Root_Certificate_Authority_2017.pem
Adding debian:Trustwave_Global_ECC_P384_Certification_Authority.pem
Adding debian:DigiCert_Global_Root_G3.pem
Adding debian:ISRG_Root_X1.pem
Adding debian:SSL.com_EV_Root_Certification_Authority_ECC.pem
Adding debian:GDCA_TrustAUTH_R5_ROOT.pem
Adding debian:Go_Daddy_Class_2_CA.pem
Adding debian:GTS_Root_R1.pem
Adding debian:COMODO_ECC_Certification_Authority.pem
Adding debian:NetLock_Arany_=Class_Gold=_Főtanúsítvány.pem
Adding debian:emSign_Root_CA_-_G1.pem
Adding debian:UCA_Global_G2_Root.pem
Adding debian:QuoVadis_Root_CA_2_G3.pem
Adding debian:Certum_Trusted_Network_CA_2.pem
Adding debian:IdenTrust_Public_Sector_Root_CA_1.pem
Adding debian:Entrust.net_Premium_2048_Secure_Server_CA.pem
Adding debian:QuoVadis_Root_CA_2.pem
Adding debian:ACCVRAIZ1.pem
Adding debian:TeliaSonera_Root_CA_v1.pem
Adding debian:SecureTrust_CA.pem
Adding debian:OISTE_WISeKey_Global_Root_GB_CA.pem
Adding debian:ePKI_Root_Certification_Authority.pem
Adding debian:AffirmTrust_Networking.pem
Adding debian:TWCA_Global_Root_CA.pem
Adding debian:Hellenic_Academic_and_Research_Institutions_ECC_RootCA_2015.pem
Adding debian:Staat_der_Nederlanden_EV_Root_CA.pem
Adding debian:QuoVadis_Root_CA_3_G3.pem
Adding debian:TUBITAK_Kamu_SM_SSL_Kok_Sertifikasi_-_Surum_1.pem
Adding debian:D-TRUST_Root_Class_3_CA_2_2009.pem
Adding debian:Chambers_of_Commerce_Root_-_2008.pem
Adding debian:certSIGN_ROOT_CA.pem
Adding debian:emSign_Root_CA_-_C1.pem
Adding debian:QuoVadis_Root_CA.pem
Adding debian:GlobalSign_Root_CA_-_R6.pem
Adding debian:Amazon_Root_CA_1.pem
Adding debian:Trustis_FPS_Root_CA.pem
Adding debian:TWCA_Root_Certification_Authority.pem
Adding debian:IdenTrust_Commercial_Root_CA_1.pem
Adding debian:Starfield_Root_Certificate_Authority_-_G2.pem
Adding debian:SwissSign_Silver_CA_-_G2.pem
Adding debian:certSIGN_Root_CA_G2.pem
Adding debian:e-Szigno_Root_CA_2017.pem
Adding debian:DigiCert_Assured_ID_Root_G3.pem
Adding debian:COMODO_Certification_Authority.pem
Adding debian:Buypass_Class_3_Root_CA.pem
Adding debian:AffirmTrust_Premium.pem
Adding debian:CA_Disig_Root_R2.pem
Adding debian:QuoVadis_Root_CA_3.pem
Adding debian:UCA_Extended_Validation_Root.pem
Adding debian:Amazon_Root_CA_3.pem
Adding debian:emSign_ECC_Root_CA_-_C3.pem
Adding debian:GeoTrust_Primary_Certification_Authority_-_G2.pem
Adding debian:Secure_Global_CA.pem
Adding debian:Amazon_Root_CA_4.pem
Adding debian:Comodo_AAA_Services_root.pem
Adding debian:DigiCert_Assured_ID_Root_G2.pem
Adding debian:Starfield_Services_Root_Certificate_Authority_-_G2.pem
Adding debian:AffirmTrust_Commercial.pem
Adding debian:Starfield_Class_2_CA.pem
Adding debian:Sonera_Class_2_Root_CA.pem
Adding debian:EC-ACC.pem
Adding debian:TrustCor_RootCert_CA-1.pem
Adding debian:Security_Communication_RootCA2.pem
Adding debian:Entrust_Root_Certification_Authority_-_EC1.pem
Adding debian:DigiCert_Global_Root_CA.pem
Adding debian:Hellenic_Academic_and_Research_Institutions_RootCA_2011.pem
Adding debian:GlobalSign_Root_CA_-_R2.pem
Adding debian:OISTE_WISeKey_Global_Root_GC_CA.pem
Adding debian:Hellenic_Academic_and_Research_Institutions_RootCA_2015.pem
Adding debian:SSL.com_Root_Certification_Authority_RSA.pem
Adding debian:Izenpe.com.pem
Adding debian:Entrust_Root_Certification_Authority_-_G2.pem
Adding debian:Microsoft_RSA_Root_Certificate_Authority_2017.pem
Adding debian:Atos_TrustedRoot_2011.pem
done.
Processing triggers for libc-bin (2.27-3ubuntu1.4) ...
Processing triggers for ca-certificates (20210119~18.04.2) ...
Updating certificates in /etc/ssl/certs...
0 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...

done.
done.
root@0873d84aae90:/home/bmogilefsky/Documents/Code/apt-buildpack/fixtures/bret# cp /etc/ssl/certs/java/cacerts .
root@0873d84aae90:/home/bmogilefsky/Documents/Code/apt-buildpack/fixtures/bret# exit

The question I still have is: Is that the right thing to do? By including the ca-certificates and ca-certificates-java packages in our apt.yml file, we have everything we need to generate the file in the right place ourselves. It will take some fiddling with all the env vars that usr/sbin/update-ca-certificates expects, and possibly a manual invocation of etc/ca-certificates/update.d/jks-keystore. (For reference, see the postinst script for ca-certificates-java.)

Still a mystery: Why doesn't the libsaxon-java package-provided usr/share/java/saxon.jar work? Why do we have to curl the upstream version from Maven?

@jbrown-xentity
Copy link
Contributor

apt-test.zip
We don't want to manage this test case long term, but don't want to lose it either, so I'm leaving it zipped here. The zip file contains everything you would need to test setting up java using apt on cloud.gov. This will be integrated into catalog and deployed with a PR (coming soon).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants