Once: CLI 명령 결과를 캐시합니다

Once: Cache CLI commands

github.com/alex0ptr ▲ 88 댓글 37 baquero

요약

Once는 명령 결과를 정해 둔 시간 동안 메모리에 보관해 같은 명령을 다시 실행하지 않게 합니다.

GitHub 사용자 alex0ptr가 Go로 만든 맥·리눅스용 오픈소스 도구입니다. 1Password에서 비밀값을 읽을 때마다 지문으로 승인해야 하는 불편을 줄이려고 만들었습니다.

왜 중요한가

  • 오래 도는 코딩 에이전트가 승인 대기로 멈추지 않으면서도 비밀값을 파일에 남기지 않는 방법을 제시합니다.
  • 결과를 디스크가 아닌 메모리에만 두는 점이 bkt 같은 비슷한 도구와 다릅니다.

핵심 내용

  • once --ttl 8h -- 명령 형태로 쓰며, 첫 실행의 표준 출력을 유효 시간(TTL) 동안 재사용합니다.
  • 결과는 사용자별 데몬(백그라운드에서 도는 프로그램)의 메모리에만 두고, 항목이 모두 만료되면 데몬도 꺼집니다.
  • 캐시 키는 테넌트 키(캐시를 나누는 이름표), 작업 디렉터리, 명령과 인자를 묶어 만듭니다.
  • 실패한 명령은 캐시하지 않으며, 64MiB가 넘는 출력은 저장하지 않고 그대로 넘깁니다.
  • 같은 사용자의 다른 프로세스는 캐시를 쓸 수 있고, 문서는 이를 의도한 설계라고 설명합니다.

HN 반응

  • 에이전트를 돌릴 때마다 승인 클릭에 지쳤다는 공감과, 승인된 비밀값을 캐시하면 노출 기간이 늘어난다는 보안 우려가 맞섰습니다.
  • 셸 스크립트 memo나 bkt처럼 비슷한 도구를 이미 쓴다는 댓글이 많았고, 작성자는 디스크에 쓰지 않는 점이 차이라고 답했습니다.

댓글

30개 표시 · 전체 37개
  1. ShakataGaNai HN

    세상에. 에이전트랑 op read라니. 와, 대박이네요.

    처음엔 그냥 가벼운 호기심으로 눌러 봤어요. 그런데 1Password 예시를 보는 순간 번개를 맞은 것 같았어요.

    저는 뭐든 "올바른 방식"으로 하려는 편이라서, 비밀 값은 디스크에 두지 않고 gitops에 이것저것 다 갖춰서 해요. 개인 프로젝트도 마찬가지고요. 그런데 API 키랑 에이전트를 같이 쓰다 보면 정말 답답해질 때가 많거든요. "테스트를 돌릴 때마다 손목시계로 승인 누르는 거 15번씩 하는 게 지겨우니까, 1Password 자격 증명을 .env에 써 놓고 앞으로는 .env를 쓰라"고 에이전트한테 말한 횟수는 차마 밝히지 못하겠네요.

  2. alex0ptr HN

    어머니만 다른 형제님을 만났네요. 저 같은 워크플로를 쓰는 사람이 아무도 없을까 봐 걱정했거든요. :)

  3. aktau HN

    이런 도구는 정말 쓸모가 많습니다. 저도 memo라는 직접 만든 도구를 쓰는데, 그냥 셸 스크립트입니다: https://github.com/aktau/dotfiles/blob/master/bin/memo

    이 도구는 https://news.ycombinator.com/item?id=45670052 에서 이야기된 적이 있고, 다른 분들이 각자 만든 도구(bkt(1), up(1) 같은 것)를 소개하기도 했습니다.

    제가 보기에 주된 차이점은 이렇습니다:

      - memo doesn't need to be built (its a shell script)
      - once keeps output cache in a running daemon. By contrast, memo stores content under /tmp with whatever the best compression available is (it prefers zstd). There's trade-offs in that. More pareto-optimal from the security front may be to have a sort of session key and to compress-then-encrypt files on disk.
    
  4. thomascountz HN

    안녕하세요! 예전에 HN에서 보고 나서 선생님의 셸 스크립트를 쓰고 있습니다. 정말 편해서 이제는 기본 내장 명령처럼 손이 가고요, 설계도 마음에 듭니다(읽으면서 배운 것도 몇 가지 있습니다)!

  5. __MatrixMan__ HN

    저는 애플리케이션이 출력에 관한 메타데이터를 충분히 노출해서, 제가 따로 지정하지 않아도 OS가 다시 실행해야 하는지 알 수 있는 날을 꿈꿉니다.

    NixOS는 빌드에서 이걸 해 주지만, 임의의 프로세스로 일반화된 건 본 적이 없습니다.

  6. jedbrooke HN

    함수형 프로그래밍의 발상이 바로 그렇습니다. 순수 함수는 출력이 오직 입력에만 좌우되고 숨은 상태가 없는 함수라서, 이전에 계산한 모든 것을 입력 -> 출력 룩업 테이블로 캐시해 둘 수 있습니다. 까다로운 건 메모리, 디스크, 네트워크 등을 읽고 쓰는 것은 더 이상 순수 함수가 아니라서 쉽게 캐시할 수 없다는 점입니다.

  7. __MatrixMan__ HN

    파일시스템이 의존하는 비트가 바뀌었는지 추적하다가, 바뀌었으면 캐시를 무효화하면 될 것 같은데요.

    네트워크 스택도 "지난번에 해시 0xabcdef123455짜리 59MB를 줬는데, 호출한 쪽에 캐시된 사본을 줘도 될까, 아니면 바뀌었나?" 같은 걸 처리할 수 있을 거고요. 그러면 데이터를 가져와 변환하는 bash 파이프라인을 다듬는 동안 데이터는 딱 한 번만 가져오게 되죠.

    스캐너 같은 주변 장치도 이전 원본이 아직 그대로 있는지, 새 원본이 올라왔는지 알 수 있는 위치에 있으니, 스캔할 새 물건이 있을 때만 다시 스캔하게 만들 수 있고요.

    저는 FP를 좋아하지만, 그걸 OS 수준에서 갖추는 건 완전히 새로운 일이 될 겁니다.

  8. PinkSheep HN

    ...CoW 파일시스템이랑 결합해서 시간을 거슬러 갈 수 있게 하지 않는 한은요 :)

  9. jchw HN

    많은 경우 다른 용도도 Nix 빌드 시스템에 억지로 끼워 맞출 수는 있어요. 성공 정도는 제각각이고, 복잡한 문제도 한둘이 아니지만요.

  10. xuhu HN

    명령 앞에 "once"를 붙이지 않고도 이게 동작하면 좋겠습니다. 특히 출력이 장황한 명령을 실행하고 나서 거기서 뭔가를 grep하고 싶어질 때요. 터미널에는 출력이 스크롤백 버퍼에 있으니, 아마 이렇게 실행할 수 있게 해 주는 "output" 명령만 만들면 될 것 같습니다:

        $ cmake ..
        $ output | grep "libssl version"
    
  11. lelanthran HN

    저는 vim과 nvim 안에서 bash를 돌립니다. 언제든 vim으로 빠져나와서 스크롤된 기록 전체를 버퍼처럼 쓸 수 있습니다.

  12. ctippett HN

    Fish 셸의 fish_preexec, fish_postexec 이벤트 훅으로 비슷하게 할 수 있을 것 같습니다.

    수정: 아니네요, 안 되겠습니다. 실행한 명령만 받을 수 있고 출력은 받지 못합니다.

  13. stirfish HN

    preexec이랑 tee를 쓰면 안 될까요?

  14. deadbunny HN

    터미널에서 캐시 무효화를 다뤄 보는 게 늘 소원이었어요.

  15. _doctor_love HN

    "메모이제이션된 CLI"라고 부르세요. 훨씬 멋져 보이거든요.

  16. giancarlostoro HN

    대표적인 사용 사례: 읽을 때마다 지문으로 승인하지 않고 1Password에서 비밀 값 읽기.

    글쎄요, 그건 좀 아닌 것 같은데요, 형씨.

  17. alex0ptr HN

    맞아요. 그런데 다른 방법이 떠오르지 않아서요. 오래 도는 에이전트를 지원하면서, 비밀 값을 파일에 남기거나 기본적으로 환경 변수에 노출하지 않으려면 달리 어떻게 해야 할까요? 이렇게 하면 에이전트가 자격 증명을 처음 요청하기 전에 저한테 알림이 오거든요.

  18. mehackernewsacc HN

    https://secretspec.dev/ 가 그 용도에 맞을까요?

  19. alex0ptr HN

    꽤 멋져 보이네요. 캐싱까지 지원하고요. 더 자세히 살펴볼게요. 고맙습니다.

  20. stryan HN

    Fnox(mise를 만든 jdx의 도구)는 비밀 값을 가져와서, 결과를 age로 암호화한 로컬 파일이나 백그라운드 데몬(메모리에만 보관)에 캐시해 반복 조회를 줄여 줍니다. 데몬도 터미널 인스턴스마다 따로 뜨는 걸로 알고 있어서, 비밀 값을 한 번 가져와도 세션 전체에 저장되지는 않습니다.

    완벽한 해결책은 아니지만, 비밀 값을 환경 변수에 두지 않으면서도 (저는 지금까지) 불편함이 거의 없었습니다.

  21. giancarlostoro HN

    비밀 값을 유출할 수도 있는 바로 그 에이전트한테요? 해커에게 열쇠 꾸러미를 통째로 열어 주는 캐시된 세션을 쥐여 주고 싶지는 않습니다.

    저는 보안 사고의 주된 원인이 될 걸 만드느니 불편함으로 지키는 보안을 택하겠습니다.

  22. alex0ptr HN

    한 번 승인했다면 이미 유출됐을 수 있다고 가정해야 하죠. 에이전트나 테넌트가 이미 가진 걸 다시 요청하는 거라면 캐시가 달라지는 건 별로 없어요.

  23. giancarlostoro HN

    아주 짧고 잠깐이어야 할 접근 가능 시간을 조금 열어 주게 되죠.

  24. hecomo HN

    정말 멋져 보입니다. 만들어 주셔서 고맙습니다.

    저는 비슷하게 CLI 출력을 잡아 두는 용도로 이걸 써 왔습니다. https://github.com/dimo414/bkt

    두 도구를 어떻게 보시는지, 그리고 어느 한쪽을 써야 할 만한 좋은 이유가 뭔지 궁금합니다. (once가 더 활발하게 개발되고 있다는 점일까요? bkt는 1년째 활동이 없습니다.)

  25. alex0ptr HN

    와, 정말 비슷하네요. 눈에 띄는 차이는 캐시된 결과를 디렉터리에 쓴다는 점인 것 같은데, 그게 바로 제가 피하고 싶었던 거예요. 그러니 무엇을 캐시하고 싶은지에 따라 다르겠죠.

  26. baquero HN

    캐시하고 싶은 CLI 호출이 있으신가요? 여기 있습니다!

  27. stingraycharles HN

    잘 설계된 것 같긴 한데, 어디에 쓰는 건가요? 사용 사례를 생각해 보려는데 상상력이 따라 주질 않네요.

  28. adregan HN

    저는 비슷한 일을 하는 작은 fish 함수를 쓰고 있습니다. 출력을 XDG_CACHE_HOME 안의 파일에 저장합니다. 예시에 나온 비밀번호나 토큰 같은 민감한 항목에는 쓰지 않겠지만, 네트워크에서 데이터를 가져와야 하는 스크립트에는 씁니다.

    예를 들어 PR 생성을 자동화하는 스크립트가 있는데, GitHub에서 저장소의 사용 가능한 라벨을 가져와 fzf 다중 선택으로 보여 줍니다. 라벨은 TTL을 일주일로 해서 저장해 두기 때문에 매번 가져올 필요가 없고, 스크립트가 파일의 나이를 원하는 TTL과 비교해 무효화합니다.

    다른 프로그램을 보강하는 데 유용하다고 생각하고, 보통 CLI에서 직접 쓰지는 않습니다.

  29. frizlab HN

    README의 예시로 보면, 비밀번호나 TouchID 확인을 요구하는 보안 저장소에서 비밀 값을 가져와 API로 토큰을 받아 오는 용도일 것 같습니다.

    다른 흥미로운 용도가 있을지는 잘 모르겠습니다. 저는 아무리 생각해도 떠오르지 않네요.

  30. alex0ptr HN

    네, 맞습니다. 에이전트를 오래 돌려 두면 빌드 스크립트에서 제 승인을 기다리느라 멈춰 버려서 특히 답답해요.

    저는 그저 제 자격 증명과 비밀 값을 파일시스템에 남기고 싶지 않을 뿐이에요.

    수정: direnv와 mise를 많이 쓰다 보니, 값을 바꿔 가며 자격 증명을 다시 불러오는 일이 흔합니다.

Hacker News에서 보기 ↗