New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@flydotio/dockerfile

Package Overview
Dependencies
Maintainers
1
Versions
58
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@flydotio/dockerfile - npm Package Compare versions

Comparing version 0.2.11 to 0.2.12

templates/litefs.yml.ejs

189

fly.js

@@ -0,1 +1,2 @@

import crypto from 'node:crypto'
import fs from 'node:fs'

@@ -5,2 +6,4 @@ import path from 'node:path'

import chalk from 'chalk'
import { GDF } from './gdf.js'

@@ -11,24 +14,90 @@

run() {
const flyToml = path.join(this._appdir, 'fly.toml')
if (!this.flySetup()) return
// create volume for sqlite3
if (this.sqlite3) this.flyMakeVolume()
// attach consul for litefs
if (this.litefs) this.flyAttachConsul(this.flyApp)
// set secrets for remix apps
if (this.remix) this.flyRemixSecrets(this.flyApp)
// set up for deploy
if (fs.existsSync('.github/workflows/deploy.yml')) {
this.flyGithubPrep()
}
}
// Verify that fly.toml exists, flyctl is in the path, extract appname
// and secrets, and save information into this object.
flySetup() {
this.flyTomlFile = path.join(this._appdir, 'fly.toml')
// ensure fly.toml exists
if (!fs.existsSync(flyToml)) return
if (!fs.existsSync(this.flyTomlFile)) return
// create volume for sqlite3
if (this.sqlite3) this.fly_make_volume(flyToml)
// read fly.toml
this.flyToml = fs.readFileSync(this.flyTomlFile, 'utf-8')
// parse app name from fly.toml
this.flyApp = this.flyToml.match(/^app\s*=\s*"?([-\w]+)"?/m)?.[1]
// see if flyctl is in the path
const paths = (process.env.PATH || '')
.replace(/"/g, '')
.split(path.delimiter)
.filter(Boolean)
const exe = 'flyctl'
const extensions = (process.env.PATHEXT || '').split(';')
const candidates = function * () {
for (const dir of paths) {
for (const ext of extensions) {
yield path.join(dir, exe + ext)
}
}
}
this.flyctl = null
for (const file of candidates()) {
try {
fs.accessSync(file, fs.constants.X_OK)
this.flyctl = file
break
} catch {
}
}
if (!this.flyctl) return
if (this.flyctl.includes(' ')) this.flyctl = JSON.stringify(this.flyctl)
// get a list of secrets
if (this.flyApp) {
try {
this.flySecrets = JSON.parse(
execSync(`${this.flyctl} secrets list --json`, { encoding: 'utf8' })
).map(secret => secret.Name)
} catch {
return // likely got an error like "Could not find App"
}
}
return true
}
// add volume to fly.toml and create it if app exists
fly_make_volume(flyToml) {
let toml = fs.readFileSync(flyToml, 'utf-8')
flyMakeVolume() {
// add a [mounts] section if one is not already present
if (!toml.includes('[mounts]')) {
toml += '\n[mounts]\n source = "data"\n destination="/data"\n'
fs.writeFileSync(flyToml, toml)
if (!this.flyToml.includes('[mounts]')) {
this.flyToml += '\n[mounts]\n source = "data"\n destination="/data"\n'
fs.writeFileSync(this.flyTomlFile, this.flyToml)
}
// parse app name from fly.toml, bailing if not found
const app = toml.match(/^app\s*=\s*"?([-\w]+)"?/m)?.[1]
if (!app) return
// bail if there is no app
if (!this.flyApp) return

@@ -39,3 +108,3 @@ // parse list of existing machines. This may fail if there are none.

machines = JSON.parse(
execSync(`flyctl machines list --app ${app} --json`, { encoding: 'utf8' }))
execSync(`${this.flyctl} machines list --app ${this.flyApp} --json`, { encoding: 'utf8' }))
} catch { }

@@ -45,3 +114,3 @@

const volumes = JSON.parse(
execSync(`flyctl volumes list --app ${app} --json`, { encoding: 'utf8' }))
execSync(`${this.flyctl} volumes list --app ${this.flyApp} --json`, { encoding: 'utf8' }))

@@ -64,3 +133,3 @@ // count the number of volumes needed in each region

execSync(
`flyctl volumes create data --app ${app} --region ${region}`,
`${this.flyctl} volumes create data --app ${this.flyApp} --region ${region}`,
{ stdio: 'inherit' }

@@ -71,2 +140,90 @@ )

}
// add volume to fly.toml and create it if app exists
flyAttachConsul(app) {
if (!app) return
// bail if v1 app
if (this.flyToml.includes('enable_consul')) return // v1-ism
// see if secret is already set?
if (this.flySecrets.includes('FLY_CONSUL_URL')) return
console.log(`${chalk.bold.green('execute'.padStart(11))} flyctl consul attach`)
execSync(
`${this.flyctl} consul attach --app ${app}`,
{ stdio: 'inherit' }
)
}
// set various secrets for Remix (and Epic Stack) applications
flyRemixSecrets(app) {
let secrets = this.flySecrets
if (app !== this.flyApp) {
// get a list of secrets for selected app
try {
secrets = JSON.parse(
execSync(`${this.flyctl} secrets list --app ${app} --json`, { encoding: 'utf8' })
).map(secret => secret.Name)
} catch {
return // likely got an error like "Could not find App"
}
}
const required = [
'SESSION_SECRET',
'ENCRYPTION_SECRET',
'INTERNAL_COMMAND_TOKEN'
]
for (const name of required) {
if (secrets.includes(name)) return
if (name !== 'SESSION_SECRET' && !this.epicStack) continue
const value = crypto.randomBytes(32).toString('hex')
console.log(`${chalk.bold.green('execute'.padStart(11))} flyctl secrets set ${name}`)
execSync(
`${this.flyctl} secrets set ${name}=${value} --app ${app}`,
{ stdio: 'inherit' }
)
}
}
// prep for deployment via github actions, inclusing settting up a staging app
flyGithubPrep() {
const deploy = fs.readFileSync('.github/workflows/deploy.yml', 'utf-8')
if (!fs.existsSync('.git')) {
console.log(`${chalk.bold.green('execute'.padStart(11))} git init`)
execSync('git init', { stdio: 'inherit' })
}
if (deploy.includes('🚀 Deploy Staging') && deploy.includes('-staging')) {
const stagingApp = `${this.flyApp}-staging`
try {
const apps = JSON.parse(
execSync(`${this.flyctl} apps list --json`, { encoding: 'utf8' })
)
const base = apps.find(app => app.Name === this.flyApp)
if (base && !apps.find(app => app.Name === stagingApp)) {
const cmd = `apps create ${stagingApp} --org ${base.Organization.Slug}`
console.log(`${chalk.bold.green('execute'.padStart(11))} flyctl ${cmd}`)
execSync(`${this.flyctl} ${cmd}`, { stdio: 'inherit' })
}
} catch {
return // likely got an error like "Could not find App"
}
// attach consul for litefs
if (this.litefs) this.flyAttachConsul(stagingApp)
// set secrets for remix apps
if (this.remix) this.flyRemixSecrets(stagingApp)
}
}
})

@@ -12,2 +12,14 @@ import fs from 'node:fs'

// defaults for all the flags that will be saved
export const defaults = {
distroless: false,
ignoreScripts: false,
legacyPeerDeps: false,
link: true,
litefs: false,
port: 0,
swap: '',
windows: false
}
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))

@@ -51,2 +63,7 @@

// Is this an EpicStack application?
get epicStack() {
return !!this.#pj['epic-stack']
}
// Does this application use prisma?

@@ -81,5 +98,22 @@ get prisma() {

return !!this.#pj.dependencies?.sqlite3 ||
!!this.#pj.dependencies?.['better-sqlite3']
!!this.#pj.dependencies?.['better-sqlite3'] ||
this.litefs
}
// Does this application use litefs?
get litefs() {
return this.options.litefs ||
!!this.#pj.dependencies?.['litefs-js']
}
// packages needed for deployment
get deployPackages() {
const packages = []
if (this.litefs) packages.push('ca-certificates', 'fuse3')
if (this.remix && this.sqlite3) packages.push('sqlite3')
return packages.sort()
}
// what node version should be used?

@@ -135,3 +169,9 @@ get nodeVersion() {

for (const file of ['package-lock.json', 'pnpm-lock.yaml', 'yarn.lock']) {
const files = [
'package-lock.json', '.npmrc',
'pnpm-lock.yaml',
'yarn.lock', '.yarnrc'
]
for (const file of files) {
if (fs.existsSync(path.join(this._appdir, file))) {

@@ -142,3 +182,3 @@ result.push(file)

return result
return result.sort()
}

@@ -286,3 +326,2 @@

const parsed = ShellQuote.parse(start)
if (parsed[0] === 'node') parsed.shift()
return parsed

@@ -333,2 +372,12 @@ }

// Tabs vs spaces
get usingTabs() {
return this.remix
}
// ESM vs CJS
get typeModule() {
return this.#pj.type === 'module'
}
// Port to be used

@@ -341,3 +390,2 @@ get port() {

if (this.gatsby) port = 8080
if (this.remix) port = 8080

@@ -347,2 +395,10 @@ return port

get configDir() {
if (this.remix && fs.existsSync('./other')) {
return 'other/'
} else {
return ''
}
}
// render each template and write to the destination dir

@@ -357,8 +413,17 @@ async run(appdir, options = {}) {

// select and render templates
const templates = ['Dockerfile.ejs']
if (this.entrypoint) templates.unshift('docker-entrypoint.ejs')
const templates = {
'Dockerfile.ejs': 'Dockerfile'
}
for (const template of templates) {
const dest = await this.#writeTemplateFile(template)
if (this.entrypoint) {
templates['docker-entrypoint.ejs'] = `${this.configDir}docker-entrypoint.js`
}
if (this.litefs) {
templates['litefs.yml.ejs'] = `${this.configDir}litefs.yml`
}
for (const [template, filename] of Object.entries(templates)) {
const dest = await this.#writeTemplateFile(template, filename)
if (template === 'docker-entrypoint.ejs') fs.chmodSync(dest, 0o755)

@@ -375,3 +440,3 @@ }

} catch {
await this.#writeTemplateFile('.dockerignore.ejs')
await this.#writeTemplateFile('.dockerignore.ejs', '.dockerignore')
}

@@ -387,5 +452,4 @@ }

// write template file, prompting when there is a conflict
async #writeTemplateFile(template) {
async #writeTemplateFile(template, name) {
const proposed = await ejs.renderFile(path.join(GDF.templates, template), this)
const name = template.replace(/\.ejs$/m, '')
const dest = path.join(this._appdir, name)

@@ -392,0 +456,0 @@

24

index.js

@@ -5,3 +5,2 @@ #!/usr/bin/env node

import process from 'node:process'
import url from 'node:url'

@@ -11,16 +10,5 @@ import yargs from 'yargs'

import { GDF } from './gdf.js'
import { GDF, defaults } from './gdf.js'
import './fly.js'
// defaults for all the flags that will be saved
export const defaults = {
distroless: false,
ignoreScripts: false,
legacyPeerDeps: false,
link: true,
port: 0,
swap: '',
windows: false
}
// read previous values from package.json

@@ -54,2 +42,6 @@ let pj = null

})
.option('litefs', {
describe: 'configure and enable litefs',
type: 'boolean'
})
.option('link', {

@@ -99,6 +91,2 @@ describe: 'use COPY --link whenever possible',

// generate dockerfile and related artifacts
// if (process.argv[1] === url.fileURLToPath(import.meta.url)) {
if (process.argv[1].endsWith('/dockerfile')) {
new GDF().run(process.cwd(), { ...defaults, ...options })
}
new GDF().run(process.cwd(), { ...defaults, ...options })
{
"name": "@flydotio/dockerfile",
"version": "0.2.11",
"version": "0.2.12",
"description": "Dockerfile generator",

@@ -5,0 +5,0 @@ "main": "./index.js",

@@ -39,2 +39,3 @@ ## Overview

* `--legacy-peer-deps` - [ignore peer dependencies](https://docs.npmjs.com/cli/v7/using-npm/config#legacy-peer-deps).
* `--litefs` - configure and enable [litefs](https://fly.io/docs/litefs/).
* `--no-link` - don't add [--link](https://docs.docker.com/engine/reference/builder/#copy---link) to COPY statements. Some tools (like at the moment, [buildah](https://www.redhat.com/en/topics/containers/what-is-buildah)) don't yet support this feature.

@@ -45,2 +46,14 @@ * `--port=n` - expose port (default may vary based on framework, but otherwise is `3000`)

## Platform specific processing
In addition to creating Dockerfiles and associated artifacts, `dockerfile-node` can run platform specific processing. At the present time the first and only platform taking advantage of this is naturally fly.io.
If, and only if, `flyctl` is installed, part of the path, and there exists a valid `fly.toml` file in the current directory, dockerfile-node will:
* configure and create volume(s) for sqlite3
* attach consul for litefs
* set secrets for remix apps
* initialize git
* define a staging app if one is mentioned in `.github/workflows/deploy.yml`
## Testing

@@ -47,0 +60,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc