Repository: FHIR/sushi
Pull request #904 (2021-08-17 23:19:55)

Use HTTPS to download packages
HL7 has turned off HTTP for some package servers -- so now is a good time to switch all our downloads to use HTTPS.  After all, it is just like HTTP but with more S.  We now connect to:
* https://packages.fhir.org
* https://packages2.fhir.org
* https://build.fhir.org

To test this, delete or rename your `~/.fhir` cache then attempt to use SUSHI to build:
* a project based on FHIR 4.0.1 (R4) - should SUCCEED on master and this branch
* a project based on FHIR 4.1.0 (R4B) - should FAIL on master but SUCCEED on this branch
* a project based on FHIR 4.6.0 (R5) - should FAIL on master but SUCCEED on this branch
* a project with a dependency using `current` version - should SUCCEED on master and this branch

cmoesel: OK @ngfreiter - 7b573db contains the error message w/ additional details as we had discussed.

Patch:
diff --git a/src/errors/CurrentPackageLoadError.ts b/src/errors/CurrentPackageLoadError.ts
index 739df07..71633d7 100644
--- a/src/errors/CurrentPackageLoadError.ts
+++ b/src/errors/CurrentPackageLoadError.ts
@@ -4,7 +4,7 @@ export class CurrentPackageLoadError extends Error implements Annotated {
   specReferences = ['https://confluence.hl7.org/display/FHIR/NPM+Package+Specification'];
   constructor(public fullPackageName: string) {
     super(
-      `The package ${fullPackageName} is not available on http://build.fhir.org/ig/qas.json, so no current version can be loaded`
+      `The package ${fullPackageName} is not available on https://build.fhir.org/ig/qas.json, so no current version can be loaded`
     );
   }
 }
diff --git a/src/fhirdefs/load.ts b/src/fhirdefs/load.ts
index cd6328d..9932749 100644
--- a/src/fhirdefs/load.ts
+++ b/src/fhirdefs/load.ts
@@ -52,7 +52,7 @@ export async function loadDependency(
 
   let packageUrl;
   if (packageName.startsWith('hl7.fhir.r5.') && version === 'current') {
-    packageUrl = `http://build.fhir.org/${packageName}.tgz`;
+    packageUrl = `https://build.fhir.org/${packageName}.tgz`;
     // TODO: Figure out how to determine if the cached package is current
     // See: https://chat.fhir.org/#narrow/stream/179252-IG-creation/topic/Registry.20for.20FHIR.20Core.20packages.20.3E.204.2E0.2E1
     if (loadedPackage) {
@@ -63,7 +63,7 @@ export async function loadDependency(
   } else if (version === 'current') {
     // Even if a local current package is loaded, we must still check that the local package date matches
     // the date on the most recent version on build.fhir.org. If the date does not match, we re-download to the cache
-    const baseUrl = 'http://build.fhir.org/ig';
+    const baseUrl = 'https://build.fhir.org/ig';
     const res = await axios.get(`${baseUrl}/qas.json`);
     const qaData: { 'package-id': string; date: string; repo: string }[] = res?.data;
     // Find matching packages and sort by date to get the most recent
@@ -112,7 +112,7 @@ export async function loadDependency(
       throw new CurrentPackageLoadError(fullPackageName);
     }
   } else if (!loadedPackage) {
-    packageUrl = `http://packages.fhir.org/${packageName}/${version}`;
+    packageUrl = `https://packages.fhir.org/${packageName}/${version}`;
 
     // If this is an R4B or R5 package, then we may need to get it from packages2 if it is not in packages
     if (/^hl7\.fhir\.r(4b|5)\./.test(packageName)) {
@@ -121,7 +121,7 @@ export async function loadDependency(
       } catch {
         // It didn't exist in the normal registry.  Fallback to packages2 registry. This should be TEMPORARY.
         // See: https://chat.fhir.org/#narrow/stream/179252-IG-creation/topic/Registry.20for.20FHIR.20Core.20packages.20.3E.204.2E0.2E1
-        packageUrl = `http://packages2.fhir.org/packages/${packageName}/${version}`;
+        packageUrl = `https://packages2.fhir.org/packages/${packageName}/${version}`;
       }
     }
   }
diff --git a/src/utils/Processing.ts b/src/utils/Processing.ts
index 9495f7d..cecd5ca 100644
--- a/src/utils/Processing.ts
+++ b/src/utils/Processing.ts
@@ -219,7 +219,16 @@ export async function loadExternalDependencies(
       return loadSupplementalFHIRPackage(EXT_PKG_TO_FHIR_PKG_MAP[dep.packageId], defs);
     } else {
       return loadDependency(dep.packageId, dep.version, defs).catch(e => {
-        logger.error(`Failed to load ${dep.packageId}#${dep.version}: ${e.message}`);
+        let message = `Failed to load ${dep.packageId}#${dep.version}: ${e.message}`;
+        if (/certificate/.test(e.message)) {
+          message +=
+            '\n\nSometimes this error occurs in corporate or educational environments that use proxies and/or SSL ' +
+            'inspection.\nTroubleshooting tips:\n' +
+            '  1. If a non-proxied network is available, consider connecting to that network instead.\n' +
+            '  2. Set NODE_EXTRA_CA_CERTS as described at https://bit.ly/3ghJqJZ (RECOMMENDED).\n' +
+            '  3. Disable certificate validation as described at https://bit.ly/3syjzm7 (NOT RECOMMENDED).\n';
+        }
+        logger.error(message);
       });
     }
   });


Test patch:
diff --git a/test/fhirdefs/load.test.ts b/test/fhirdefs/load.test.ts
index 34055c2..7ef0946 100644
--- a/test/fhirdefs/load.test.ts
+++ b/test/fhirdefs/load.test.ts
@@ -74,7 +74,7 @@ describe('#loadDependency()', () => {
   let cachePath: string;
   beforeAll(() => {
     axiosSpy = jest.spyOn(axios, 'get').mockImplementation((uri: string): any => {
-      if (uri === 'http://build.fhir.org/ig/qas.json') {
+      if (uri === 'https://build.fhir.org/ig/qas.json') {
         return {
           data: [
             {
@@ -127,8 +127,8 @@ describe('#loadDependency()', () => {
           ]
         };
       } else if (
-        uri === 'http://build.fhir.org/ig/HL7/US-Core-R4/package.manifest.json' ||
-        (uri.startsWith('http://build.fhir.org/ig/sushi/sushi-test') && uri.endsWith('json'))
+        uri === 'https://build.fhir.org/ig/HL7/US-Core-R4/package.manifest.json' ||
+        (uri.startsWith('https://build.fhir.org/ig/sushi/sushi-test') && uri.endsWith('json'))
       ) {
         return {
           data: {
@@ -136,14 +136,14 @@ describe('#loadDependency()', () => {
           }
         };
       } else if (
-        uri === 'http://packages.fhir.org/sushi-test/0.2.0' ||
-        uri === 'http://build.fhir.org/ig/sushi/sushi-test-old/package.tgz' ||
-        uri === 'http://build.fhir.org/ig/HL7/US-Core-R4/package.tgz' ||
-        uri === 'http://build.fhir.org/hl7.fhir.r5.core.tgz' ||
-        uri === 'http://packages2.fhir.org/packages/hl7.fhir.r4b.core/4.1.0' ||
-        uri === 'http://packages.fhir.org/hl7.fhir.r4b.core/4.3.0' ||
-        uri === 'http://packages2.fhir.org/packages/hl7.fhir.r5.core/4.5.0' ||
-        uri === 'http://packages.fhir.org/hl7.fhir.r4.core/4.0.1'
+        uri === 'https://packages.fhir.org/sushi-test/0.2.0' ||
+        uri === 'https://build.fhir.org/ig/sushi/sushi-test-old/package.tgz' ||
+        uri === 'https://build.fhir.org/ig/HL7/US-Core-R4/package.tgz' ||
+        uri === 'https://build.fhir.org/hl7.fhir.r5.core.tgz' ||
+        uri === 'https://packages2.fhir.org/packages/hl7.fhir.r4b.core/4.1.0' ||
+        uri === 'https://packages.fhir.org/hl7.fhir.r4b.core/4.3.0' ||
+        uri === 'https://packages2.fhir.org/packages/hl7.fhir.r5.core/4.5.0' ||
+        uri === 'https://packages.fhir.org/hl7.fhir.r4.core/4.0.1'
       ) {
         return {
           data: {
@@ -156,8 +156,8 @@ describe('#loadDependency()', () => {
     });
     axiosHeadSpy = jest.spyOn(axios, 'head').mockImplementation((uri: string): any => {
       if (
-        uri === 'http://packages.fhir.org/hl7.fhir.r4b.core/4.1.0' ||
-        uri === 'http://packages.fhir.org/hl7.fhir.r5.core/4.5.0'
+        uri === 'https://packages.fhir.org/hl7.fhir.r4b.core/4.1.0' ||
+        uri === 'https://packages.fhir.org/hl7.fhir.r5.core/4.5.0'
       ) {
         throw 'Not Found';
       } else {
@@ -199,7 +199,7 @@ describe('#loadDependency()', () => {
       'The package sushi-test#0.2.0 could not be loaded locally or from the FHIR package registry'
     ); // the package is never actually added to the cache, since tar is mocked
     expect(axiosSpy.mock.calls).toEqual([
-      ['http://packages.fhir.org/sushi-test/0.2.0', { responseType: 'arraybuffer' }]
+      ['https://packages.fhir.org/sushi-test/0.2.0', { responseType: 'arraybuffer' }]
     ]);
     expect(ensureDirSpy.mock.calls[0]).toEqual([path.join('foo', 'sushi-test#0.2.0')]);
     expect(tarSpy.mock.calls[0][0].cwd).toBe(path.join('foo', 'sushi-test#0.2.0'));
@@ -210,7 +210,7 @@ describe('#loadDependency()', () => {
       'The package hl7.fhir.r4.core#4.0.1 could not be loaded locally or from the FHIR package registry'
     ); // the package is never actually added to the cache, since tar is mocked
     expect(axiosSpy.mock.calls).toEqual([
-      ['http://packages.fhir.org/hl7.fhir.r4.core/4.0.1', { responseType: 'arraybuffer' }]
+      ['https://packages.fhir.org/hl7.fhir.r4.core/4.0.1', { responseType: 'arraybuffer' }]
     ]);
     expect(ensureDirSpy.mock.calls[0]).toEqual([path.join('foo', 'hl7.fhir.r4.core#4.0.1')]);
     expect(tarSpy.mock.calls[0][0].cwd).toBe(path.join('foo', 'hl7.fhir.r4.core#4.0.1'));
@@ -222,7 +222,7 @@ describe('#loadDependency()', () => {
     ); // the package is never actually added to the cache, since tar is mocked
     expect(axiosSpy.mock.calls).toEqual([
       [
-        'http://packages2.fhir.org/packages/hl7.fhir.r4b.core/4.1.0',
+        'https://packages2.fhir.org/packages/hl7.fhir.r4b.core/4.1.0',
         { responseType: 'arraybuffer' }
       ]
     ]);
@@ -235,7 +235,7 @@ describe('#loadDependency()', () => {
       'The package hl7.fhir.r4b.core#4.3.0 could not be loaded locally or from the FHIR package registry'
     ); // the package is never actually added to the cache, since tar is mocked
     expect(axiosSpy.mock.calls).toEqual([
-      ['http://packages.fhir.org/hl7.fhir.r4b.core/4.3.0', { responseType: 'arraybuffer' }]
+      ['https://packages.fhir.org/hl7.fhir.r4b.core/4.3.0', { responseType: 'arraybuffer' }]
     ]);
     expect(ensureDirSpy.mock.calls[0]).toEqual([path.join('foo', 'hl7.fhir.r4b.core#4.3.0')]);
     expect(tarSpy.mock.calls[0][0].cwd).toBe(path.join('foo', 'hl7.fhir.r4b.core#4.3.0'));
@@ -246,7 +246,10 @@ describe('#loadDependency()', () => {
       'The package hl7.fhir.r5.core#4.5.0 could not be loaded locally or from the FHIR package registry'
     ); // the package is never actually added to the cache, since tar is mocked
     expect(axiosSpy.mock.calls).toEqual([
-      ['http://packages2.fhir.org/packages/hl7.fhir.r5.core/4.5.0', { responseType: 'arraybuffer' }]
+      [
+        'https://packages2.fhir.org/packages/hl7.fhir.r5.core/4.5.0',
+        { responseType: 'arraybuffer' }
+      ]
     ]);
     expect(ensureDirSpy.mock.calls[0]).toEqual([path.join('foo', 'hl7.fhir.r5.core#4.5.0')]);
     expect(tarSpy.mock.calls[0][0].cwd).toBe(path.join('foo', 'hl7.fhir.r5.core#4.5.0'));
@@ -260,7 +263,7 @@ describe('#loadDependency()', () => {
       /Unable to download most current version of sushi-test#0.3.0/
     );
     expect(axiosSpy.mock.calls).toEqual([
-      ['http://packages.fhir.org/sushi-test/0.3.0', { responseType: 'arraybuffer' }]
+      ['https://packages.fhir.org/sushi-test/0.3.0', { responseType: 'arraybuffer' }]
     ]);
     expect(ensureDirSpy.mock.calls).toHaveLength(0);
     expect(tarSpy.mock.calls).toHaveLength(0);
@@ -278,8 +281,8 @@ describe('#loadDependency()', () => {
       expectedDefs
     );
     expect(axiosSpy.mock.calls).toEqual([
-      ['http://build.fhir.org/ig/qas.json'],
-      ['http://build.fhir.org/ig/sushi/sushi-test/package.manifest.json']
+      ['https://build.fhir.org/ig/qas.json'],
+      ['https://build.fhir.org/ig/sushi/sushi-test/package.manifest.json']
     ]);
   });
 
@@ -288,9 +291,9 @@ describe('#loadDependency()', () => {
       'The package hl7.fhir.us.core.r4#current could not be loaded locally or from the FHIR package registry'
     ); // the package is never actually added to the cache, since tar is mocked
     expect(axiosSpy.mock.calls).toEqual([
-      ['http://build.fhir.org/ig/qas.json'],
-      ['http://build.fhir.org/ig/HL7/US-Core-R4/package.manifest.json'],
-      ['http://build.fhir.org/ig/HL7/US-Core-R4/package.tgz', { responseType: 'arraybuffer' }]
+      ['https://build.fhir.org/ig/qas.json'],
+      ['https://build.fhir.org/ig/HL7/US-Core-R4/package.manifest.json'],
+      ['https://build.fhir.org/ig/HL7/US-Core-R4/package.tgz', { responseType: 'arraybuffer' }]
     ]);
     expect(ensureDirSpy.mock.calls[0]).toEqual([path.join('foo', 'hl7.fhir.us.core.r4#current')]);
     expect(tarSpy.mock.calls[0][0].cwd).toBe(path.join('foo', 'hl7.fhir.us.core.r4#current'));
@@ -301,9 +304,12 @@ describe('#loadDependency()', () => {
       loadDependency('sushi-test-old', 'current', defs, cachePath)
     ).resolves.toBeTruthy(); // Since tar is mocked, the actual cache is not updated
     expect(axiosSpy.mock.calls).toEqual([
-      ['http://build.fhir.org/ig/qas.json'],
-      ['http://build.fhir.org/ig/sushi/sushi-test-old/package.manifest.json'],
-      ['http://build.fhir.org/ig/sushi/sushi-test-old/package.tgz', { responseType: 'arraybuffer' }]
+      ['https://build.fhir.org/ig/qas.json'],
+      ['https://build.fhir.org/ig/sushi/sushi-test-old/package.manifest.json'],
+      [
+        'https://build.fhir.org/ig/sushi/sushi-test-old/package.tgz',
+        { responseType: 'arraybuffer' }
+      ]
     ]);
     expect(ensureDirSpy.mock.calls[0][0]).toEqual(path.join(cachePath, 'sushi-test-old#current'));
     expect(tarSpy.mock.calls[0][0].cwd).toBe(path.join(cachePath, 'sushi-test-old#current'));
@@ -314,7 +320,7 @@ describe('#loadDependency()', () => {
       'The package hl7.fhir.r5.core#current could not be loaded locally or from the FHIR package registry'
     ); // the package is never actually added to the cache, since tar is mocked
     expect(axiosSpy.mock.calls).toEqual([
-      ['http://build.fhir.org/hl7.fhir.r5.core.tgz', { responseType: 'arraybuffer' }]
+      ['https://build.fhir.org/hl7.fhir.r5.core.tgz', { responseType: 'arraybuffer' }]
     ]);
     expect(ensureDirSpy.mock.calls[0]).toEqual([path.join('foo', 'hl7.fhir.r5.core#current')]);
     expect(tarSpy.mock.calls[0][0].cwd).toBe(path.join('foo', 'hl7.fhir.r5.core#current'));
@@ -331,10 +337,10 @@ describe('#loadDependency()', () => {
       loadDependency('sushi-test-no-download', 'current', defs, cachePath)
     ).resolves.toEqual(expectedDefs);
     expect(axiosSpy.mock.calls).toEqual([
-      ['http://build.fhir.org/ig/qas.json'],
-      ['http://build.fhir.org/ig/sushi/sushi-test-no-download/package.manifest.json'],
+      ['https://build.fhir.org/ig/qas.json'],
+      ['https://build.fhir.org/ig/sushi/sushi-test-no-download/package.manifest.json'],
       [
-        'http://build.fhir.org/ig/sushi/sushi-test-no-download/package.tgz',
+        'https://build.fhir.org/ig/sushi/sushi-test-no-download/package.tgz',
         { responseType: 'arraybuffer' }
       ]
     ]);
@@ -364,9 +370,12 @@ describe('#loadDependency()', () => {
         )
     ).toBeTruthy();
     expect(axiosSpy.mock.calls).toEqual([
-      ['http://build.fhir.org/ig/qas.json'],
-      ['http://build.fhir.org/ig/sushi/sushi-test-old/package.manifest.json'],
-      ['http://build.fhir.org/ig/sushi/sushi-test-old/package.tgz', { responseType: 'arraybuffer' }]
+      ['https://build.fhir.org/ig/qas.json'],
+      ['https://build.fhir.org/ig/sushi/sushi-test-old/package.manifest.json'],
+      [
+        'https://build.fhir.org/ig/sushi/sushi-test-old/package.tgz',
+        { responseType: 'arraybuffer' }
+      ]
     ]);
     expect(ensureDirSpy.mock.calls[0]).toEqual([path.join(cachePath, 'sushi-test-old#current')]);
     expect(tarSpy.mock.calls[0][0].cwd).toBe(path.join(cachePath, 'sushi-test-old#current'));
@@ -374,19 +383,19 @@ describe('#loadDependency()', () => {
 
   it('should throw CurrentPackageLoadError when a current package is not listed', async () => {
     await expect(loadDependency('hl7.fhir.us.core', 'current', defs, 'foo')).rejects.toThrow(
-      'The package hl7.fhir.us.core#current is not available on http://build.fhir.org/ig/qas.json, so no current version can be loaded'
+      'The package hl7.fhir.us.core#current is not available on https://build.fhir.org/ig/qas.json, so no current version can be loaded'
     );
     expect(axiosSpy.mock.calls.length).toBe(1);
-    expect(axiosSpy.mock.calls[0][0]).toBe('http://build.fhir.org/ig/qas.json');
+    expect(axiosSpy.mock.calls[0][0]).toBe('https://build.fhir.org/ig/qas.json');
   });
 
-  it('should throw CurrentPackageLoadError when http://build.fhir.org/ig/qas.json gives a bad response', async () => {
+  it('should throw CurrentPackageLoadError when https://build.fhir.org/ig/qas.json gives a bad response', async () => {
     axiosSpy.mockImplementationOnce(() => {});
     await expect(loadDependency('bad.response', 'current', defs, 'foo')).rejects.toThrow(
-      'The package bad.response#current is not available on http://build.fhir.org/ig/qas.json, so no current version can be loaded'
+      'The package bad.response#current is not available on https://build.fhir.org/ig/qas.json, so no current version can be loaded'
     );
     expect(axiosSpy.mock.calls.length).toBe(1);
-    expect(axiosSpy.mock.calls[0][0]).toBe('http://build.fhir.org/ig/qas.json');
+    expect(axiosSpy.mock.calls[0][0]).toBe('https://build.fhir.org/ig/qas.json');
   });
 });
 
diff --git a/test/ig/IGExporter.package-list.test.ts b/test/ig/IGExporter.package-list.test.ts
index 96e47d7..10d7034 100644
--- a/test/ig/IGExporter.package-list.test.ts
+++ b/test/ig/IGExporter.package-list.test.ts
@@ -36,7 +36,7 @@ describe('IGExporter', () => {
           {
             version: 'current',
             desc: 'Continuous Integration Build (latest in version control)',
-            path: 'http://build.fhir.org/ig/HL7/example-ig/',
+            path: 'https://build.fhir.org/ig/HL7/example-ig/',
             status: 'ci-build',
             current: true
           },
diff --git a/test/ig/fixtures/customized-ig/package-list.json b/test/ig/fixtures/customized-ig/package-list.json
index ab47abd..0fca7b5 100644
--- a/test/ig/fixtures/customized-ig/package-list.json
+++ b/test/ig/fixtures/customized-ig/package-list.json
@@ -7,7 +7,7 @@
     {
       "version": "current",
       "desc": "Continuous Integration Build (latest in version control)",
-      "path": "http://build.fhir.org/ig/fhir/sushi-test",
+      "path": "https://build.fhir.org/ig/fhir/sushi-test",
       "status": "ci-build",
       "current": true
     },
diff --git a/test/import/YAMLConfiguration.test.ts b/test/import/YAMLConfiguration.test.ts
index 291daf4..c7f1447 100644
--- a/test/import/YAMLConfiguration.test.ts
+++ b/test/import/YAMLConfiguration.test.ts
@@ -107,7 +107,7 @@ describe('YAMLConfiguration', () => {
         validation: ['allow-any-extensions', 'no-broken-links']
       });
       expect(config.history).toEqual({
-        current: 'http://build.fhir.org/ig/HL7/example-ig/',
+        current: 'https://build.fhir.org/ig/HL7/example-ig/',
         '1.0.0': {
           fhirversion: '4.0.1',
           date: '2020-03-06',
diff --git a/test/import/fixtures/example-config.yaml b/test/import/fixtures/example-config.yaml
index 61925ad..47992c5 100644
--- a/test/import/fixtures/example-config.yaml
+++ b/test/import/fixtures/example-config.yaml
@@ -200,7 +200,7 @@ history:
   #   desc: Continuous Integration Build (latest in version control)
   #   status: ci-build
   #   current: true
-  current: http://build.fhir.org/ig/HL7/example-ig/
+  current: https://build.fhir.org/ig/HL7/example-ig/
   # All other versions need each of their values fully specified.
   # See: https://confluence.hl7.org/pages/viewpage.action?pageId=66928420#FHIRIGPackageListdoco-PublicationObject
   1.0.0:
diff --git a/test/import/importConfiguration.test.ts b/test/import/importConfiguration.test.ts
index 584c600..fa36e4c 100644
--- a/test/import/importConfiguration.test.ts
+++ b/test/import/importConfiguration.test.ts
@@ -171,7 +171,7 @@ describe('importConfiguration', () => {
           {
             version: 'current',
             desc: 'Continuous Integration Build (latest in version control)',
-            path: 'http://build.fhir.org/ig/HL7/example-ig/',
+            path: 'https://build.fhir.org/ig/HL7/example-ig/',
             status: 'ci-build',
             current: true
           },
@@ -1894,7 +1894,7 @@ describe('importConfiguration', () => {
       minYAML.title = 'HL7 FHIR Implementation Guide: Minimal IG Release 1 - US Realm | STU1';
       minYAML.description = 'Minimal IG exercises only required fields in a SUSHI configuration.';
       minYAML.history = {
-        current: 'http://build.fhir.org/ig/HL7/minimal-ig/'
+        current: 'https://build.fhir.org/ig/HL7/minimal-ig/'
       };
       const config = importConfiguration(minYAML, 'test-config.yaml');
       expect(config.history).toEqual({
@@ -1906,7 +1906,7 @@ describe('importConfiguration', () => {
           {
             version: 'current',
             desc: 'Continuous Integration Build (latest in version control)',
-            path: 'http://build.fhir.org/ig/HL7/minimal-ig/',
+            path: 'https://build.fhir.org/ig/HL7/minimal-ig/',
             status: 'ci-build',
             current: true
           }
@@ -1920,7 +1920,7 @@ describe('importConfiguration', () => {
         current: {
           fhirversion: '4.0.1',
           date: '2020-04-01',
-          path: 'http://build.fhir.org/ig/HL7/example-ig/',
+          path: 'https://build.fhir.org/ig/HL7/example-ig/',
           sequence: 'STU 2'
         }
       };
@@ -1936,7 +1936,7 @@ describe('importConfiguration', () => {
             fhirversion: '4.0.1',
             date: '2020-04-01',
             desc: 'Continuous Integration Build (latest in version control)',
-            path: 'http://build.fhir.org/ig/HL7/example-ig/',
+            path: 'https://build.fhir.org/ig/HL7/example-ig/',
             status: 'ci-build',
             sequence: 'STU 2',
             current: true
@@ -1956,7 +1956,7 @@ describe('importConfiguration', () => {
           fhirversion: '4.0.1',
           date: '2020-04-01',
           desc: 'CI Build Release',
-          path: 'http://build.fhir.org/ig/HL7/example-ig/',
+          path: 'https://build.fhir.org/ig/HL7/example-ig/',
           status: 'ci-build',
           sequence: 'STU 2',
           current: true
@@ -1991,7 +1991,7 @@ describe('importConfiguration', () => {
             fhirversion: '4.0.1',
             date: '2020-04-01',
             desc: 'CI Build Release',
-            path: 'http://build.fhir.org/ig/HL7/example-ig/',
+            path: 'https://build.fhir.org/ig/HL7/example-ig/',
             status: 'ci-build',
             sequence: 'STU 2',
             current: true
@@ -2058,7 +2058,7 @@ describe('importConfiguration', () => {
     });
     it('should report invalid history.[version].status code', () => {
       minYAML.history = {
-        current: 'http://build.fhir.org/ig/HL7/minimal-ig/',
+        current: 'https://build.fhir.org/ig/HL7/minimal-ig/',
         '1.0.0': {
           fhirversion: '4.0.1',
           date: '2020-03-06',
@@ -2086,7 +2086,7 @@ describe('importConfiguration', () => {
     });
     it('should report an error if history.[version].date is missing', () => {
       minYAML.history = {
-        current: 'http://build.fhir.org/ig/HL7/minimal-ig/',
+        current: 'https://build.fhir.org/ig/HL7/minimal-ig/',
         '1.0.0': {
           fhirversion: '4.0.1',
           desc: 'STU 1 Release',
@@ -2112,7 +2112,7 @@ describe('importConfiguration', () => {
     });
     it('should report an error if history.[version].desc is missing', () => {
       minYAML.history = {
-        current: 'http://build.fhir.org/ig/HL7/minimal-ig/',
+        current: 'https://build.fhir.org/ig/HL7/minimal-ig/',
         '1.0.0': {
           fhirversion: '4.0.1',
           date: '2020-03-06',
@@ -2138,7 +2138,7 @@ describe('importConfiguration', () => {
     });
     it('should report an error if history.[version].path is missing', () => {
       minYAML.history = {
-        current: 'http://build.fhir.org/ig/HL7/minimal-ig/',
+        current: 'https://build.fhir.org/ig/HL7/minimal-ig/',
         // @ts-ignore Type '...' is not assignable to type ...
         '1.0.0': {
           fhirversion: '4.0.1',
@@ -2165,7 +2165,7 @@ describe('importConfiguration', () => {
     });
     it('should report an error if history.[version].status is missing', () => {
       minYAML.history = {
-        current: 'http://build.fhir.org/ig/HL7/minimal-ig/',
+        current: 'https://build.fhir.org/ig/HL7/minimal-ig/',
         '1.0.0': {
           fhirversion: '4.0.1',
           date: '2020-03-06',
@@ -2191,7 +2191,7 @@ describe('importConfiguration', () => {
     });
     it('should report an error if history.[version].sequence is missing', () => {
       minYAML.history = {
-        current: 'http://build.fhir.org/ig/HL7/minimal-ig/',
+        current: 'https://build.fhir.org/ig/HL7/minimal-ig/',
         '1.0.0': {
           fhirversion: '4.0.1',
           date: '2020-03-06',
@@ -2217,7 +2217,7 @@ describe('importConfiguration', () => {
     });
     it('should report an error if history.[version].fhirVersion is missing', () => {
       minYAML.history = {
-        current: 'http://build.fhir.org/ig/HL7/minimal-ig/',
+        current: 'https://build.fhir.org/ig/HL7/minimal-ig/',
         '1.0.0': {
           date: '2020-03-06',
           desc: 'STU 1 Release',
diff --git a/test/utils/Processing.test.ts b/test/utils/Processing.test.ts
index 524db2e..a20c1df 100644
--- a/test/utils/Processing.test.ts
+++ b/test/utils/Processing.test.ts
@@ -320,6 +320,8 @@ describe('Processing', () => {
             if (/^hl7.fhir.(r2|r3|r4|r4b|r5|us).core$/.test(packageName)) {
               FHIRDefs.packages.push(`${packageName}#${version}`);
               return Promise.resolve(FHIRDefs);
+            } else if (/^self-signed.package$/.test(packageName)) {
+              throw new Error('self signed certificate in certificate chain');
             } else {
               throw new PackageLoadError(`${packageName}#${version}`);
             }
@@ -468,6 +470,27 @@ describe('Processing', () => {
         expect(loggerSpy.getLastMessage('error')).toMatch(
           /Failed to load hl7\.does\.not\.exist#current/s
         );
+        // But don't log the error w/ details about proxies
+        expect(loggerSpy.getLastMessage('error')).not.toMatch(/SSL/s);
+      });
+    });
+
+    it('should log a more detailed error when it fails to load a dependency due to certificate issue', () => {
+      const selfSignedDependencyConfig = cloneDeep(minimalConfig);
+      selfSignedDependencyConfig.dependencies = [
+        { packageId: 'self-signed.package', version: '1.0.0' }
+      ];
+      const defs = new FHIRDefinitions();
+      return loadExternalDependencies(defs, selfSignedDependencyConfig).then(() => {
+        expect(defs.packages.length).toBe(1);
+        expect(defs.packages).toContain('hl7.fhir.r4.core#4.0.1');
+        expect(loggerSpy.getLastMessage('error')).toMatch(
+          /Failed to load self-signed\.package#1\.0\.0/s
+        );
+        // AND it should log the detailed message about SSL
+        expect(loggerSpy.getLastMessage('error')).toMatch(
+          /Sometimes this error occurs in corporate or educational environments that use proxies and\/or SSL inspection/s
+        );
       });
     });
 
@@ -481,6 +504,8 @@ describe('Processing', () => {
         expect(loggerSpy.getLastMessage('error')).toMatch(
           /Failed to load hl7\.fhir\.r4\.core: No version specified\./s
         );
+        // But don't log the error w/ details about proxies
+        expect(loggerSpy.getLastMessage('error')).not.toMatch(/SSL/s);
       });
     });
   });