mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 06:43:06 +00:00
fix(media): repara rota do Garage no deploy
This commit is contained in:
parent
4be1c0923b
commit
b3c6caada2
8 changed files with 331 additions and 0 deletions
1
docs/changelog/2026-09-25-media-upload-share-link.md
Normal file
1
docs/changelog/2026-09-25-media-upload-share-link.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
**Upload de capa no admin de Links de compartilhamento ganha rota S3 validada no deploy (2026-09-25):** uploads dependiam de uma rota S3 inacessível após mudança de topologia; o deploy agora sonda o Garage pela imagem migrator, escolhe um gateway IPv4 funcional via override por ambiente e testa a rota novamente após o healthcheck, com rollback em falha. Env files e credenciais não são reescritos; sem migration ou mudança de UI. Regressões unitárias, ShareLink 25/25, e2e do link 6/6 e `pnpm gate:fast` (424 arquivos / 4698 testes) verdes. PR, CI, deploy e a confirmação em produção estão pendentes; a aprovação humana de produção continua obrigatória.
|
||||
|
|
@ -120,6 +120,40 @@ clone do workspace não precisa de credencial. No GitHub ficam apenas os
|
|||
secrets de integração: `FORGEJO_API_TOKEN` (flips pós-merge) e
|
||||
`CURSOR_API_KEY` (archive helper, dormente).
|
||||
|
||||
## Garage e uploads de mídia
|
||||
|
||||
O runtime usa o endpoint S3 do arquivo de ambiente. O endpoint documentado
|
||||
`http://host.docker.internal:3900` depende do gateway da rede Docker; depois de
|
||||
uma alteração nas redes, o alias `host-gateway` pode resolver para um gateway
|
||||
que não alcança o Garage. Nesse caso, o upload do Payload fica esperando o
|
||||
`PutObject` e a interface permanece em **Enviando...**, embora o PostgreSQL e o
|
||||
resto do site estejam saudáveis.
|
||||
|
||||
O `scripts/deploy-homeserver.sh` trata esse caminho antes das migrations: ele
|
||||
sonda o endpoint a partir da imagem migrator, testa os gateways IPv4 da rede
|
||||
`stack_default` quando o alias falha e gera um override operacional por
|
||||
ambiente (`~/stack/docker-compose.media-production.yml` ou
|
||||
`~/stack/docker-compose.media-staging.yml`). O override altera somente
|
||||
`S3_ENDPOINT` nos dois serviços do ambiente selecionado; credenciais e arquivos
|
||||
de ambiente não são reescritos. Depois do rollout, o mesmo endpoint é sondado de
|
||||
dentro do container e uma falha executa o rollback.
|
||||
|
||||
O probe é fail-closed: se nenhum gateway responder, o deploy para antes de
|
||||
aplicar migrations. O override é um artefato operacional do stack, não um
|
||||
arquivo versionado. Para diagnosticar o estado atual:
|
||||
|
||||
```bash
|
||||
ssh homeserver
|
||||
cd ~/stack
|
||||
set -a; source ~/stack/teqo-1313.env; set +a
|
||||
docker network inspect -f '{{range .IPAM.Config}}{{println .Gateway}}{{end}}' stack_default
|
||||
docker exec teqo-1313 node -e "fetch(process.env.S3_ENDPOINT, {signal: AbortSignal.timeout(5000)}).then(r => console.log(r.status)).catch(e => { console.error(e); process.exit(1) })"
|
||||
```
|
||||
|
||||
O comando `docker exec` deve concluir em poucos segundos, mesmo que o Garage
|
||||
responda `403` à raiz; timeout ou `ENETUNREACH` significa que o caminho do
|
||||
container ainda não alcança o bucket.
|
||||
|
||||
## Staging (OPS103)
|
||||
|
||||
Alvo real e descartável para validar o SHA (migração/build/rollout/smoke) antes
|
||||
|
|
|
|||
82
docs/postmortems/2026-09-25-media-upload-share-link.md
Normal file
82
docs/postmortems/2026-09-25-media-upload-share-link.md
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
# Post-mortem: upload de capa em Links de compartilhamento bloqueado pela rota S3
|
||||
|
||||
> Template do `/bug-fix`. Preencha com fatos apurados; o que não for apurado fica "não apurado" — nunca invente.
|
||||
|
||||
## Registro
|
||||
|
||||
| Campo | Valor |
|
||||
| ------------------- | ----------------------------------------------------------------------------- |
|
||||
| Data do post-mortem | 2026-09-25 |
|
||||
| Severidade | alta (bloqueia uploads de mídia em produção) |
|
||||
| Ambiente | prod (sintoma e diagnóstico read-only) + dev/worktree (reprodução e correção) |
|
||||
| Issue(s) | sem Issue |
|
||||
| PR do fix | pendente |
|
||||
| Detectado por | humano |
|
||||
|
||||
## Timeline
|
||||
|
||||
| Momento | Data/hora | Evento |
|
||||
| ------------------ | ---------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| Início provável | não apurado | A introdução exata é não apurada. O sintoma foi reportado contra a UI da versão S29, com múltiplos destinos. |
|
||||
| Detecção | 2026-09-25, hora não apurada | O humano relatou que o envio da capa permanecia em "Enviando..." até desistir no admin de Links de compartilhamento. |
|
||||
| Diagnóstico | 2026-09-25 | Diagnóstico read-only em produção associou o bloqueio à rota S3 do container. |
|
||||
| Correção mergeada | pendente | Correção implementada no worktree `fix/13`; PR e CI pendentes. |
|
||||
| Deploy | pendente | O merge dispara o deploy; staging é automático e produção depende de aprovação humana. |
|
||||
| Verificado em prod | pendente — aprovação humana | CI, PR, deploy e confirmação do comportamento em produção estão pendentes. |
|
||||
|
||||
## O bug
|
||||
|
||||
Em produção, no admin de Links de compartilhamento, o envio de uma capa permanecia em **Enviando...** até a desistência. O relato ocorreu na versão S29, com múltiplos destinos.
|
||||
|
||||
O incidente não foi reproduzido com o storage local do worktree `fix/13`, em `http://localhost:3297`. O envio da capa funcionou tanto na criação de um link quanto na edição de um link com duas linhas no array `destinations`: `Imagem > Criar Novo`, arquivo, alt e Salvar resultaram em `POST /api/media 201` e upload concluído. O formulário e o array não causaram o incidente.
|
||||
|
||||
## Causa-raiz
|
||||
|
||||
O `PutObject` S3 aguardava uma rota de rede inacessível. Os logs do container em produção registravam `connect ETIMEDOUT 10.0.0.1:3900`; `host.docker.internal` resolvia para `10.0.0.1`, enquanto o gateway IPv4 `10.0.11.1` da rede `stack_default` respondia de imediato ao Garage. A topologia observada tornou o alias `host-gateway` uma rota não confiável até o Garage. A alteração que introduziu essa mudança e a origem exata do incidente são não apuradas. A configuração efetiva do UFW não foi inspecionada, portanto este documento não atribui a causa ao firewall.
|
||||
|
||||
`src/payload.config.ts:184-207` repassa `S3_ENDPOINT` ao plugin S3. `src/collections/ShareLink.ts:257-265` define apenas o campo de upload e não participa do POST de `media`. Não há base para atribuir o incidente ao S29; ele é apenas a UI contra a qual o sintoma foi reportado.
|
||||
|
||||
### 5 whys
|
||||
|
||||
1. Por que a tela fica em "Enviando..."? Porque `POST /api/media` não conclui enquanto aguarda o `PutObject`.
|
||||
2. Por que o POST não conclui? Porque a operação S3 expira ao tentar conectar em `10.0.0.1:3900`.
|
||||
3. Por que o container tenta esse endereço? Porque `host.docker.internal` resolve para `10.0.0.1` em produção.
|
||||
4. Por que essa rota falha? Porque o alias `host-gateway` deixou de alcançar o Garage após a mudança de topologia; o evento exato não foi apurado.
|
||||
5. Por que o deploy não detectou a indisponibilidade? Porque o caminho S3 não tinha um probe próprio no fluxo de deploy.
|
||||
|
||||
## Correção
|
||||
|
||||
`scripts/deploy-homeserver.sh` agora testa o endpoint S3 a partir da imagem migrator já construída, antes das migrations. Se `host.docker.internal` falhar, o script testa os gateways IPv4 de `stack_default`; o primeiro gateway acessível gera, por `scripts/lib/mediaEndpoint.mjs`, um override de Compose específico do ambiente. O override altera `S3_ENDPOINT` somente no runner e no serviço de migrations, é validado com `docker compose ... config --quiet` e passa a valer via `COMPOSE_FILE`. Arquivos de ambiente e credenciais não são reescritos.
|
||||
|
||||
Depois do healthcheck, o endpoint é sondado de dentro do container em execução; uma falha aciona o rollback. Se nenhum gateway responder, o deploy para antes das migrations. O procedimento também ficou registrado em `docs/ops/teqo-1313-deploy.md`. Nenhuma migration foi criada; o campo de `ShareLink` e a UI não foram alterados.
|
||||
|
||||
## Verificação
|
||||
|
||||
- Teste de regressão: `tests/unit/mediaEndpoint.unit.spec.ts`, 3/3; no HEAD pré-fix, o novo import de `scripts/lib/mediaEndpoint.mjs` não existia, e o spec passa com a correção.
|
||||
- Regressão do deploy: `tests/unit/deployScript.unit.spec.ts`, "repairs a broken S3 host gateway before migration and verifies the live route"; falha no estado pré-fix e passa com a correção.
|
||||
- Suíte: `pnpm gate:fast` verde, 424 arquivos e 4698 testes; integração de ShareLink 25/25; `frontendShareLink` e2e 6/6; `pnpm format:check`, `pnpm check:cycles`, `pnpm knip` e `bash -n` verdes.
|
||||
- CI: pendente; o PR ainda não foi criado.
|
||||
- Deploy: pendente de PR, CI e merge; a produção ainda depende de aprovação humana.
|
||||
- verificado em prod: pendente — aprovação humana.
|
||||
|
||||
## Prevenção
|
||||
|
||||
| Estratégia | Custo | Estado |
|
||||
| ------------------------------------------------------------------------------------- | ------ | ----------------------------------------- |
|
||||
| Probe do S3 na imagem migrator e fallback dinâmico para um gateway IPv4 acessível | barata | implementada neste worktree |
|
||||
| Probe do S3 no container em execução após o healthcheck, com rollback em falha | barata | implementada neste worktree |
|
||||
| Regressões unitárias do helper e do script, mais diagnóstico e recuperação no runbook | barata | implementada neste worktree |
|
||||
| Observabilidade contínua do S3 e alertas de falha ou latência | cara | documentada, não implementada neste fluxo |
|
||||
| Upload sintético de mídia para detectar perda da rota antes do uso humano | cara | documentada, não implementada neste fluxo |
|
||||
|
||||
**Estratégia implementada:** o deploy passa a validar a rota antes das migrations, ajustar apenas o endpoint dos serviços do ambiente selecionado e repetir a validação no container em execução. Os testes de regressão fixam a ordem e o fallback, e o runbook registra o diagnóstico.
|
||||
|
||||
**Estratégia documentada (cara):** observabilidade contínua e alertas do S3, além de upload sintético de mídia.
|
||||
|
||||
## Lições
|
||||
|
||||
- O storage local prova o caminho do formulário, mas não exercita a rota S3 de produção.
|
||||
- O campo exibido no admin apontava para `ShareLink`; a falha real ocorreu no POST de `media`. O diagnóstico precisou seguir a requisição até o `PutObject`.
|
||||
- A versão S29 é o contexto do relato, não uma origem comprovada.
|
||||
- Health do site e alcance do Garage são dependências diferentes. O deploy precisa testar a segunda antes de declarar o rollout saudável.
|
||||
- Sem inspeção do UFW, a causa fica limitada à rota observada; atribuir o incidente ao firewall seria especulativo.
|
||||
|
|
@ -63,6 +63,87 @@ fatal() {
|
|||
exit 1
|
||||
}
|
||||
|
||||
probe_media_endpoint() {
|
||||
local image="$1"
|
||||
local endpoint="$2"
|
||||
local host="${3:-}"
|
||||
local -a args=(--rm --network stack_default)
|
||||
if [ -n "$host" ]; then
|
||||
args+=(--add-host "host.docker.internal:$host")
|
||||
fi
|
||||
docker run "${args[@]}" \
|
||||
--env "S3_PROBE_ENDPOINT=$endpoint" \
|
||||
--entrypoint node \
|
||||
"$image" \
|
||||
-e 'fetch(process.env.S3_PROBE_ENDPOINT, { signal: AbortSignal.timeout(5000) }).then(() => process.exit(0)).catch(() => process.exit(1))' \
|
||||
>/dev/null 2>&1
|
||||
}
|
||||
|
||||
media_gateways() {
|
||||
docker network inspect -f '{{range .IPAM.Config}}{{println .Gateway}}{{end}}' stack_default 2>/dev/null
|
||||
}
|
||||
|
||||
ensure_media_endpoint() {
|
||||
local image="$TEQO_REGISTRY/$TEQO_IMAGE_REPO-migrator:$SHA"
|
||||
local override="$STACK_DIR/docker-compose.media-$TEQO_ENV.yml"
|
||||
|
||||
if [ -z "${S3_BUCKET:-}" ] || [ -z "${S3_ENDPOINT:-}" ] || [ -z "${S3_ACCESS_KEY_ID:-}" ] || [ -z "${S3_SECRET_ACCESS_KEY:-}" ]; then
|
||||
rm -f "$override"
|
||||
unset COMPOSE_FILE
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! node "$WORKSPACE_DIR/scripts/lib/mediaEndpoint.mjs" is-host-gateway --endpoint "$S3_ENDPOINT"; then
|
||||
if probe_media_endpoint "$image" "$S3_ENDPOINT" ""; then
|
||||
rm -f "$override"
|
||||
unset COMPOSE_FILE
|
||||
return 0
|
||||
fi
|
||||
fatal "configured S3 endpoint is unreachable from the Docker network"
|
||||
fi
|
||||
|
||||
if probe_media_endpoint "$image" "$S3_ENDPOINT" "host-gateway"; then
|
||||
rm -f "$override"
|
||||
unset COMPOSE_FILE
|
||||
return 0
|
||||
fi
|
||||
|
||||
local gateway
|
||||
while IFS= read -r gateway; do
|
||||
if [[ ! "$gateway" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
|
||||
continue
|
||||
fi
|
||||
if probe_media_endpoint "$image" "$S3_ENDPOINT" "$gateway"; then
|
||||
if ! node "$WORKSPACE_DIR/scripts/lib/mediaEndpoint.mjs" \
|
||||
--container "$TEQO_CONTAINER" \
|
||||
--migrate-service "$TEQO_MIGRATE_SERVICE" \
|
||||
--endpoint "$S3_ENDPOINT" \
|
||||
--gateway "$gateway" >"$override"; then
|
||||
rm -f "$override"
|
||||
fatal "failed to render media endpoint override"
|
||||
fi
|
||||
if ! docker compose -f "$STACK_DIR/docker-compose.yml" -f "$override" config --quiet; then
|
||||
rm -f "$override"
|
||||
fatal "media endpoint override is invalid"
|
||||
fi
|
||||
export COMPOSE_FILE="$STACK_DIR/docker-compose.yml:$override"
|
||||
say "repairing S3 route for $TEQO_CONTAINER with the reachable stack gateway"
|
||||
return 0
|
||||
fi
|
||||
done < <(media_gateways)
|
||||
|
||||
fatal "no reachable IPv4 gateway for the configured S3 endpoint"
|
||||
}
|
||||
|
||||
smoke_media_endpoint() {
|
||||
if [ -z "${S3_BUCKET:-}" ] || [ -z "${S3_ENDPOINT:-}" ] || [ -z "${S3_ACCESS_KEY_ID:-}" ] || [ -z "${S3_SECRET_ACCESS_KEY:-}" ]; then
|
||||
return 0
|
||||
fi
|
||||
docker exec "$TEQO_CONTAINER" node -e \
|
||||
'fetch(process.env.S3_ENDPOINT, { signal: AbortSignal.timeout(5000) }).then(() => process.exit(0)).catch(() => process.exit(1))' \
|
||||
>/dev/null 2>&1 || rollback "S3 endpoint missing or unreachable from $TEQO_CONTAINER"
|
||||
}
|
||||
|
||||
# --- environment map (OPS103) -------------------------------------------
|
||||
# Production values are the pre-OPS103 literals: the canonical invocation
|
||||
# `bash scripts/deploy-homeserver.sh <sha>` (no TEQO_ENV) behaves exactly as
|
||||
|
|
@ -207,6 +288,7 @@ docker push "$TEQO_REGISTRY/$TEQO_IMAGE_REPO-migrator:$SHA"
|
|||
# --- compose swap (backup first; failures from here roll back) ----------
|
||||
|
||||
compose="$STACK_DIR/docker-compose.yml"
|
||||
ensure_media_endpoint
|
||||
backup="$compose.pre-$SHA"
|
||||
cp "$compose" "$backup"
|
||||
# Image lines: the env-specific repo names cannot touch the other
|
||||
|
|
@ -276,6 +358,8 @@ for _ in $(seq 1 30); do
|
|||
done
|
||||
[ "$health" = "healthy" ] || rollback "container not healthy after 300s (status: $health)"
|
||||
|
||||
smoke_media_endpoint
|
||||
|
||||
# --- feature env audit (non-fatal) --------------------------------------
|
||||
# A missing feature key never fails the boot: the capability degrades
|
||||
# silently (AI theme search/titles/transcription, forgot-password e-mail,
|
||||
|
|
|
|||
69
scripts/lib/mediaEndpoint.mjs
Normal file
69
scripts/lib/mediaEndpoint.mjs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import { isIPv4 } from 'node:net'
|
||||
|
||||
const HOST_GATEWAY = 'host.docker.internal'
|
||||
const SERVICE_NAME = /^[A-Za-z0-9_.-]+$/
|
||||
|
||||
const parseEndpoint = (endpoint) => {
|
||||
try {
|
||||
return new URL(endpoint)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export const isHostGatewayEndpoint = (endpoint) => {
|
||||
const url = parseEndpoint(endpoint)
|
||||
return url?.hostname === HOST_GATEWAY
|
||||
}
|
||||
|
||||
export const replaceEndpointHost = (endpoint, host) => {
|
||||
const url = parseEndpoint(endpoint)
|
||||
if (!url || !isIPv4(host)) throw new Error('Invalid media endpoint host')
|
||||
const hadExplicitPath = url.pathname !== '/'
|
||||
url.hostname = host
|
||||
const resolved = url.toString()
|
||||
return hadExplicitPath || !resolved.endsWith('/') ? resolved : resolved.slice(0, -1)
|
||||
}
|
||||
|
||||
export const renderMediaEndpointOverride = ({ container, migrateService, endpoint, gateway }) => {
|
||||
if (
|
||||
!SERVICE_NAME.test(container) ||
|
||||
!SERVICE_NAME.test(migrateService) ||
|
||||
container === migrateService ||
|
||||
!isHostGatewayEndpoint(endpoint) ||
|
||||
!isIPv4(gateway)
|
||||
) {
|
||||
throw new Error('Invalid media endpoint override')
|
||||
}
|
||||
|
||||
const resolvedEndpoint = replaceEndpointHost(endpoint, gateway)
|
||||
return [
|
||||
'services:',
|
||||
` ${container}:`,
|
||||
' environment:',
|
||||
` S3_ENDPOINT: ${JSON.stringify(resolvedEndpoint)}`,
|
||||
` ${migrateService}:`,
|
||||
' environment:',
|
||||
` S3_ENDPOINT: ${JSON.stringify(resolvedEndpoint)}`,
|
||||
'',
|
||||
].join('\n')
|
||||
}
|
||||
|
||||
if (process.argv[1]?.endsWith('/mediaEndpoint.mjs')) {
|
||||
const args = process.argv.slice(2)
|
||||
const value = (name) => {
|
||||
const index = args.indexOf(name)
|
||||
return index === -1 ? '' : args[index + 1]
|
||||
}
|
||||
if (args[0] === 'is-host-gateway') {
|
||||
process.exit(isHostGatewayEndpoint(value('--endpoint')) ? 0 : 1)
|
||||
}
|
||||
process.stdout.write(
|
||||
renderMediaEndpointOverride({
|
||||
container: value('--container'),
|
||||
migrateService: value('--migrate-service'),
|
||||
endpoint: value('--endpoint'),
|
||||
gateway: value('--gateway'),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
@ -83,6 +83,7 @@ export const SCRIPTS_SPEC_PINNED = [
|
|||
'scripts/lib/issues-panel.mjs',
|
||||
'scripts/lib/markdown-ansi.mjs',
|
||||
'scripts/lib/mediaBinaries.mjs',
|
||||
'scripts/lib/mediaEndpoint.mjs',
|
||||
'scripts/lib/plansOnlyClosesGuard.mjs',
|
||||
'scripts/lib/playwright-e2e-args.mjs',
|
||||
'scripts/lib/portalTransparenciaEmendas.mjs',
|
||||
|
|
|
|||
|
|
@ -147,6 +147,31 @@ describe('scripts/deploy-homeserver.sh (OPS53 deploy pipeline)', () => {
|
|||
expect(callIndex).toBeLessThan(smokeIndex)
|
||||
})
|
||||
|
||||
it('repairs a broken S3 host gateway before migration and verifies the live route', () => {
|
||||
for (const fragment of [
|
||||
'ensure_media_endpoint',
|
||||
'probe_media_endpoint',
|
||||
'docker network inspect',
|
||||
'--add-host "host.docker.internal:$host"',
|
||||
'docker compose -f "$STACK_DIR/docker-compose.yml" -f "$override" config --quiet',
|
||||
'docker-compose.media-$TEQO_ENV.yml',
|
||||
'export COMPOSE_FILE=',
|
||||
'smoke_media_endpoint',
|
||||
]) {
|
||||
expect(script, fragment).toContain(fragment)
|
||||
}
|
||||
|
||||
const ensureCall = script.indexOf('ensure_media_endpoint\nbackup=')
|
||||
const migrateCall = script.indexOf('docker compose --profile maintenance run --rm')
|
||||
const healthCall = script.indexOf('[ "$health" = "healthy" ]')
|
||||
const smokeCall = script.indexOf('\nsmoke_media_endpoint\n')
|
||||
expect(ensureCall).toBeGreaterThan(-1)
|
||||
expect(ensureCall).toBeLessThan(migrateCall)
|
||||
expect(smokeCall).toBeGreaterThan(healthCall)
|
||||
expect(script).not.toContain('10.0.11.1')
|
||||
expect(script).not.toContain('10.0.0.1')
|
||||
})
|
||||
|
||||
it('never echoes secret values (no set -x, passwords only via stdin/secrets)', () => {
|
||||
expect(script).not.toMatch(/^set -x\b/m)
|
||||
expect(script).not.toContain('echo "$DATABASE_URL"')
|
||||
|
|
|
|||
35
tests/unit/mediaEndpoint.unit.spec.ts
Normal file
35
tests/unit/mediaEndpoint.unit.spec.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import {
|
||||
isHostGatewayEndpoint,
|
||||
renderMediaEndpointOverride,
|
||||
replaceEndpointHost,
|
||||
} from '../../scripts/lib/mediaEndpoint.mjs'
|
||||
|
||||
describe('media endpoint deploy fallback', () => {
|
||||
it('recognizes only the documented host gateway endpoint for automatic repair', () => {
|
||||
expect(isHostGatewayEndpoint('http://host.docker.internal:3900')).toBe(true)
|
||||
expect(isHostGatewayEndpoint('http://10.0.11.1:3900')).toBe(false)
|
||||
expect(isHostGatewayEndpoint('not-a-url')).toBe(false)
|
||||
})
|
||||
|
||||
it('renders an override for both services of only the selected environment', () => {
|
||||
const override = renderMediaEndpointOverride({
|
||||
container: 'teqo-1313',
|
||||
migrateService: 'teqo-1313-migrate',
|
||||
endpoint: 'http://host.docker.internal:3900',
|
||||
gateway: '10.0.11.1',
|
||||
})
|
||||
|
||||
expect(override).toContain('teqo-1313:')
|
||||
expect(override).toContain('teqo-1313-migrate:')
|
||||
expect(override).toContain('S3_ENDPOINT: "http://10.0.11.1:3900"')
|
||||
expect(override).not.toContain('teqo-staging')
|
||||
})
|
||||
|
||||
it('preserves the endpoint port and path when replacing the host', () => {
|
||||
expect(replaceEndpointHost('http://host.docker.internal:3900/media', '10.0.11.1')).toBe(
|
||||
'http://10.0.11.1:3900/media',
|
||||
)
|
||||
})
|
||||
})
|
||||
Loading…
Reference in a new issue